Merge "Add a switch to configure APEX payload type" into main
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index cd9d76d..4d3b546 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -89,6 +89,8 @@
else:
regex = r'\b(%s)\b' % re.escape(target)
if any(re.search(regex, opt) for opt in test_discovery_zip_regexes):
+ get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
+ else:
get_metrics_agent().report_optimized_target(target)
if self._unused_target_exclusion_enabled(
diff --git a/core/Makefile b/core/Makefile
index 5e0d4df..92dd86d 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1654,6 +1654,8 @@
$(ALL_DEFAULT_INSTALLED_MODULES))
INTERNAL_VENDOR_RAMDISK_TARGET := $(call intermediates-dir-for,PACKAGING,vendor_boot)/vendor_ramdisk.cpio$(RAMDISK_EXT)
+vendor_ramdisk_intermediates :=$= $(call intermediates-dir-for,PACKAGING,vendor_ramdisk)
+$(eval $(call write-partition-file-list,$(vendor_ramdisk_intermediates)/file_list.txt,$(TARGET_VENDOR_RAMDISK_OUT),$(INTERNAL_VENDOR_RAMDISK_FILES)))
# Exclude recovery files in the default vendor ramdisk if including a standalone
# recovery ramdisk in vendor_boot.
diff --git a/core/config.mk b/core/config.mk
index 485e8cc..b546ea1 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -1307,10 +1307,6 @@
SOONG_VARIABLES :=
SOONG_EXTRA_VARIABLES :=
--include external/ltp/android/ltp_package_list.mk
-DEFAULT_DATA_OUT_MODULES := ltp $(ltp_packages)
-.KATI_READONLY := DEFAULT_DATA_OUT_MODULES
-
include $(BUILD_SYSTEM)/dumpvar.mk
ifdef BOARD_VNDK_VERSION
diff --git a/core/layoutlib_data.mk b/core/layoutlib_data.mk
index 06735df..dabcfb2 100644
--- a/core/layoutlib_data.mk
+++ b/core/layoutlib_data.mk
@@ -106,6 +106,7 @@
_layoutlib_font_config_files := $(sort $(wildcard frameworks/base/data/fonts/*.xml))
_layoutlib_fonts_files := $(filter $(TARGET_OUT)/fonts/%.ttf $(TARGET_OUT)/fonts/%.ttc $(TARGET_OUT)/fonts/%.otf, $(INTERNAL_SYSTEMIMAGE_FILES))
_layoutlib_keyboard_files := $(sort $(wildcard frameworks/base/data/keyboards/*.kcm))
+_layoutlib_hyphen_files := $(filter $(TARGET_OUT)/usr/hyphen-data/%.hyb, $(INTERNAL_SYSTEMIMAGE_FILES))
# Find out files disted with layoutlib in Soong.
### Filter out static libraries for Windows and files already handled in make.
@@ -135,6 +136,13 @@
echo data/keyboards/$(notdir $f),frameworks/base/data/keyboards,prebuilt_etc,,,,,$f,,, >> $@; \
)
+ $(foreach f,$(_layoutlib_hyphen_files), \
+ $(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
+ $(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
+ $(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
+ echo data/hyphen-data/$(notdir $f),$(_module_path),$(_soong_module_type),,,,,$f,,, >> $@; \
+ )
+
$(foreach f,$(_layoutlib_files_disted_by_soong), \
$(eval _prebuilt_module_file := $(call word-colon,1,$f)) \
$(eval _dist_file := $(call word-colon,2,$f)) \
@@ -163,7 +171,7 @@
.PHONY: layoutlib-sbom
layoutlib-sbom: $(LAYOUTLIB_SBOM)/layoutlib.spdx.json
-$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
+$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(_layoutlib_hyphen_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
rm -rf $@
$(GEN_SBOM) --output_file $@ --metadata $(LAYOUTLIB_SBOM)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --module_name "layoutlib" --json
diff --git a/core/main.mk b/core/main.mk
index f96cf04..624df49 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1399,6 +1399,7 @@
$(INSTALLED_RAMDISK_TARGET) \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_INIT_BOOT_IMAGE_TARGET) \
+ $(INSTALLED_DTBOIMAGE_TARGET) \
$(INSTALLED_RADIOIMAGE_TARGET) \
$(INSTALLED_DEBUG_RAMDISK_TARGET) \
$(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
diff --git a/core/soong_config.mk b/core/soong_config.mk
index d823905..2f69d06 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -427,6 +427,22 @@
$(call add_json_str, BoardFlashLogicalBlockSize, $(BOARD_FLASH_LOGICAL_BLOCK_SIZE))
$(call add_json_str, BoardFlashEraseBlockSize, $(BOARD_FLASH_ERASE_BLOCK_SIZE))
$(call add_json_bool, BuildingVbmetaImage, $(BUILDING_VBMETA_IMAGE))
+
+ # boot image stuff
+ $(call add_json_bool, BuildingRamdiskImage, $(filter true,$(BUILDING_RAMDISK_IMAGE)))
+ $(call add_json_bool, ProductBuildBootImage, $(filter true,$(PRODUCT_BUILD_BOOT_IMAGE)))
+ $(call add_json_str, ProductBuildVendorBootImage, $(PRODUCT_BUILD_VENDOR_BOOT_IMAGE))
+ $(call add_json_bool, ProductBuildInitBootImage, $(filter true,$(PRODUCT_BUILD_INIT_BOOT_IMAGE)))
+ $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
+ $(call add_json_str, BoardPrebuiltBootimage, $(BOARD_PREBUILT_BOOT_IMAGE))
+ $(call add_json_str, BoardPrebuiltInitBootimage, $(BOARD_PREBUILT_INIT_BOOT_IMAGE))
+ $(call add_json_str, BoardBootimagePartitionSize, $(BOARD_BOOTIMAGE_PARTITION_SIZE))
+ $(call add_json_str, BoardInitBootimagePartitionSize, $(BOARD_INIT_BOOTIMAGE_PARTITION_SIZE))
+ $(call add_json_str, BoardBootHeaderVersion, $(BOARD_BOOT_HEADER_VERSION))
+ $(call add_json_str, TargetKernelPath, $(TARGET_KERNEL_PATH))
+ $(call add_json_bool, BoardUsesGenericKernelImage, $(BOARD_USES_GENERIC_KERNEL_IMAGE))
+
+ # Avb (android verified boot) stuff
$(call add_json_bool, BoardAvbEnable, $(filter true,$(BOARD_AVB_ENABLE)))
$(call add_json_str, BoardAvbAlgorithm, $(BOARD_AVB_ALGORITHM))
$(call add_json_str, BoardAvbKeyPath, $(BOARD_AVB_KEY_PATH))
@@ -442,7 +458,6 @@
$(call end_json_map))
$(call end_json_map)
- $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
$(call add_json_bool, ProductUseDynamicPartitionSize, $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITION_SIZE)))
$(call add_json_bool, CopyImagesForTargetFilesZip, $(filter true,$(COPY_IMAGES_FOR_TARGET_FILES_ZIP)))
diff --git a/core/tasks/general-tests.mk b/core/tasks/general-tests.mk
index d6fc072..1901ed5 100644
--- a/core/tasks/general-tests.mk
+++ b/core/tasks/general-tests.mk
@@ -27,21 +27,9 @@
# Create an artifact to include all test config files in general-tests.
general_tests_configs_zip := $(PRODUCT_OUT)/general-tests_configs.zip
-# Copy kernel test modules to testcases directories
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-ltp_copy_pairs := \
- $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_host_out))
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
-
-# PHONY target to be used to build and test `vts_ltp_tests` without building full vts
-.PHONY: vts_kernel_ltp_tests
-vts_kernel_ltp_tests: $(copy_ltp_tests)
-
general_tests_shared_libs_zip := $(PRODUCT_OUT)/general-tests_host-shared-libs.zip
$(general_tests_zip) : $(general_tests_shared_libs_zip)
-$(general_tests_zip) : $(copy_ltp_tests)
-$(general_tests_zip) : PRIVATE_KERNEL_LTP_HOST_OUT := $(kernel_ltp_host_out)
$(general_tests_zip) : PRIVATE_general_tests_list_zip := $(general_tests_list_zip)
$(general_tests_zip) : .KATI_IMPLICIT_OUTPUTS := $(general_tests_list_zip) $(general_tests_configs_zip)
$(general_tests_zip) : PRIVATE_TOOLS := $(general_tests_tools)
@@ -52,7 +40,6 @@
rm -f $@ $(PRIVATE_general_tests_list_zip)
mkdir -p $(PRIVATE_INTERMEDIATES_DIR) $(PRIVATE_INTERMEDIATES_DIR)/tools
echo $(sort $(COMPATIBILITY.general-tests.FILES) $(COMPATIBILITY.general-tests.SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES)) | tr " " "\n" > $(PRIVATE_INTERMEDIATES_DIR)/list
- find $(PRIVATE_KERNEL_LTP_HOST_OUT) >> $(PRIVATE_INTERMEDIATES_DIR)/list
grep $(HOST_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/host.list || true
grep $(TARGET_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/target.list || true
grep -e .*\\.config$$ $(PRIVATE_INTERMEDIATES_DIR)/host.list > $(PRIVATE_INTERMEDIATES_DIR)/host-test-configs.list || true
diff --git a/core/tasks/tools/vts-kernel-tests.mk b/core/tasks/tools/vts-kernel-tests.mk
deleted file mode 100644
index e727dc1..0000000
--- a/core/tasks/tools/vts-kernel-tests.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2022 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.
-
--include external/ltp/android/ltp_package_list.mk
-
-include $(BUILD_SYSTEM)/tasks/tools/vts_package_utils.mk
-
-# Copy kernel test modules to testcases directories
-kernel_ltp_host_out := $(HOST_OUT_TESTCASES)/vts_kernel_ltp_tests
-kernel_ltp_vts_out := $(HOST_OUT)/$(test_suite_name)/android-$(test_suite_name)/testcases/vts_kernel_ltp_tests
-kernel_ltp_modules := \
- ltp \
- $(ltp_packages)
diff --git a/core/tasks/tools/vts_package_utils.mk b/core/tasks/tools/vts_package_utils.mk
deleted file mode 100644
index 1a819f2..0000000
--- a/core/tasks/tools/vts_package_utils.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# $(1): List of target native files to copy.
-# $(2): Copy destination directory.
-# Evaluates to a list of ":"-separated pairs src:dst.
-define target-native-copy-pairs
-$(foreach m,$(1),\
- $(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
- $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
- $(foreach i, $(sort $(_built_files)),\
- $(eval bui_ins := $(subst :,$(space),$(i)))\
- $(eval ins := $(word 2,$(bui_ins)))\
- $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
- $(eval bui := $(word 1,$(bui_ins)))\
- $(eval my_copy_dest := $(patsubst data/%,DATA/%,\
- $(patsubst system/%,DATA/%,\
- $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))))\
- $(call declare-copy-target-license-metadata,$(2)/$(my_copy_dest),$(bui))\
- $(bui):$(2)/$(my_copy_dest))))
-endef
diff --git a/core/tasks/vts-core-tests.mk b/core/tasks/vts-core-tests.mk
index 1eeb078..11bb932 100644
--- a/core/tasks/vts-core-tests.mk
+++ b/core/tasks/vts-core-tests.mk
@@ -16,15 +16,6 @@
test_suite_tradefed := vts-tradefed
test_suite_readme := test/vts/tools/vts-core-tradefed/README
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-
-ltp_copy_pairs := \
- $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_vts_out))
-
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
-
-test_suite_extra_deps := $(copy_ltp_tests)
-
include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
.PHONY: vts
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index ea49af4..b1c3def 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -885,7 +885,7 @@
}
android_system_image {
- name: "generic_system_image",
+ name: "aosp_shared_system_image",
defaults: ["system_image_defaults"],
dirs: android_rootdirs,
symlinks: android_symlinks,
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 15e4187..043a956 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -106,8 +106,12 @@
],
"postsubmit": [
{
- // aconfig_storage read api java integration tests
- "name": "aconfig_storage_read_api.test.java"
+ // aconfig_storage read functional test
+ "name": "aconfig_storage_read_functional"
+ },
+ {
+ // aconfig_storage read unit test
+ "name": "aconfig_storage_read_unit"
}
]
}
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index bfdf1a7..e2bb1ad 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -513,19 +513,11 @@
package com.android.aconfig.test;
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
- import android.os.Binder;
- import android.provider.DeviceConfig;
- import android.provider.DeviceConfig.Properties;
import android.aconfig.storage.StorageInternalReader;
- import java.nio.file.Files;
- import java.nio.file.Paths;
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags {
- private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
private static volatile boolean isCached = false;
- private static volatile boolean aconfig_test_is_cached = false;
- private static volatile boolean other_namespace_is_cached = false;
private static boolean disabledRw = false;
private static boolean disabledRwExported = false;
private static boolean disabledRwInOtherNamespace = false;
@@ -544,55 +536,6 @@
disabledRwInOtherNamespace = foundPackage ? reader.getBooleanFlagValue(3) : false;
isCached = true;
}
- private void load_overrides_aconfig_test() {
- final long ident = Binder.clearCallingIdentity();
- try {
- Properties properties = DeviceConfig.getProperties("aconfig_test");
- disabledRw =
- properties.getBoolean(Flags.FLAG_DISABLED_RW, false);
- disabledRwExported =
- properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false);
- enabledRw =
- properties.getBoolean(Flags.FLAG_ENABLED_RW, true);
- } catch (NullPointerException e) {
- throw new RuntimeException(
- "Cannot read value from namespace aconfig_test "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- } catch (SecurityException e) {
- // for isolated process case, skip loading flag value from the storage, use the default
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- aconfig_test_is_cached = true;
- }
-
- private void load_overrides_other_namespace() {
- final long ident = Binder.clearCallingIdentity();
- try {
- Properties properties = DeviceConfig.getProperties("other_namespace");
- disabledRwInOtherNamespace =
- properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false);
- } catch (NullPointerException e) {
- throw new RuntimeException(
- "Cannot read value from namespace other_namespace "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- } catch (SecurityException e) {
- // for isolated process case, skip loading flag value from the storage, use the default
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- other_namespace_is_cached = true;
- }
@Override
@com.android.aconfig.annotations.AconfigFlagAccessor
@@ -604,14 +547,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRw() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return disabledRw;
}
@@ -619,14 +556,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwExported() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return disabledRwExported;
}
@@ -634,14 +565,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!other_namespace_is_cached) {
- load_overrides_other_namespace();
- }
+ if (!isCached) {
+ init();
}
return disabledRwInOtherNamespace;
}
@@ -673,14 +598,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean enabledRw() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return enabledRw;
}
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 569a34b..82a6ebc 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -259,10 +259,6 @@
/// flag provider
pub struct FlagProvider;
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe {
- Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
get_mapped_storage_file("system", StorageFileType::PackageMap)
.and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
@@ -275,54 +271,46 @@
/// flag value cache for disabled_rw
static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
- // This will be called multiple times. Subsequent calls after the first are noops.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("aconfig_rust_codegen")
- .with_max_level(LevelFilter::Info));
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device("aconfig_rust_codegen")
+ .with_max_level(LevelFilter::Info));
- let flag_value_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 => {
- log!(Level::Error, "no context found for package com.android.aconfig.test");
- Err(format!("failed to flag package com.android.aconfig.test"))
- }
- }
- })
- });
+ let flag_value_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 => {
+ log!(Level::Error, "no context found for package com.android.aconfig.test");
+ Err(format!("failed to flag package com.android.aconfig.test"))
+ }
+ }
+ })
+ });
- match flag_value_result {
- Ok(flag_value) => {
- return flag_value;
- },
- Err(err) => {
- log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- return false;
- }
+ match flag_value_result {
+ Ok(flag_value) => {
+ return flag_value;
+ },
+ Err(err) => {
+ log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+ return false;
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.disabled_rw",
- "false") == "true"
}
});
/// flag value cache for disabled_rw_exported
static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -359,17 +347,10 @@
return false;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.disabled_rw_exported",
- "false") == "true"
- }
});
/// flag value cache for disabled_rw_in_other_namespace
static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -406,18 +387,11 @@
return false;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.other_namespace",
- "com.android.aconfig.test.disabled_rw_in_other_namespace",
- "false") == "true"
- }
});
/// flag value cache for enabled_rw
static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -454,12 +428,6 @@
return true;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.enabled_rw",
- "true") == "true"
- }
});
impl FlagProvider {
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 0ad3d97..81119f3 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -69,6 +69,7 @@
declarations: Vec<Input>,
values: Vec<Input>,
default_permission: ProtoFlagPermission,
+ allow_read_write: bool,
) -> Result<Vec<u8>> {
let mut parsed_flags = ProtoParsedFlags::new();
@@ -195,6 +196,16 @@
}
}
+ if !allow_read_write {
+ if let Some(pf) = parsed_flags
+ .parsed_flag
+ .iter()
+ .find(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
+ {
+ bail!("flag {} has permission READ_WRITE, but allow_read_write is false", pf.name());
+ }
+ }
+
// Create a sorted parsed_flags
aconfig_protos::parsed_flags::sort_parsed_flags(&mut parsed_flags);
aconfig_protos::parsed_flags::verify_fields(&parsed_flags)?;
@@ -427,14 +438,14 @@
// protect hardcoded offset reads.
// Creates a fingerprint of the flag names (which requires sorting the vector).
// Fingerprint is used by both codegen and storage files.
-pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> Result<u64> {
+pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> u64 {
flag_names.sort();
let mut hasher = SipHasher13::new();
for flag in flag_names {
hasher.write(flag.as_bytes());
}
- Ok(hasher.finish())
+ hasher.finish()
}
#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
@@ -466,7 +477,7 @@
let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
let hash_result = compute_flags_fingerprint(&mut extracted_flags);
- assert_eq!(hash_result.unwrap(), expected_fingerprint);
+ assert_eq!(hash_result, expected_fingerprint);
}
#[test]
@@ -487,7 +498,7 @@
let result_from_names = compute_flags_fingerprint(&mut flag_names_vec);
// Assert the same hash is generated for each case.
- assert_eq!(result_from_parsed_flags.unwrap(), result_from_names.unwrap());
+ assert_eq!(result_from_parsed_flags, result_from_names);
}
#[test]
@@ -497,9 +508,9 @@
let second_parsed_flags = crate::test::parse_second_package_flags();
let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
- let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags).unwrap();
+ let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags);
let mut second_extracted_flags = extract_flag_names(second_parsed_flags).unwrap();
- let second_result = compute_flags_fingerprint(&mut second_extracted_flags).unwrap();
+ let second_result = compute_flags_fingerprint(&mut second_extracted_flags);
// Different flags should have a different fingerprint.
assert_ne!(result_from_parsed_flags, second_result);
@@ -576,6 +587,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
@@ -609,6 +621,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -640,6 +653,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -647,6 +661,121 @@
"failed to parse memory: expected container argument.container, got declaration.container"
);
}
+ #[test]
+ fn test_parse_flags_no_allow_read_write_default_error() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let error = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ vec![],
+ ProtoFlagPermission::READ_WRITE,
+ false,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "flag first has permission READ_WRITE, but allow_read_write is false"
+ );
+ }
+
+ #[test]
+ fn test_parse_flags_no_allow_read_write_value_error() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let first_flag_value = r#"
+ flag_value {
+ package: "com.first"
+ name: "first"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ "#;
+ let value = vec![Input {
+ source: "memory".to_string(),
+ reader: Box::new(first_flag_value.as_bytes()),
+ }];
+ let error = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_ONLY,
+ false,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "flag first has permission READ_WRITE, but allow_read_write is false"
+ );
+ }
+
+ #[test]
+ fn test_parse_flags_no_allow_read_write_success() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let first_flag_value = r#"
+ flag_value {
+ package: "com.first"
+ name: "first"
+ state: DISABLED
+ permission: READ_ONLY
+ }
+ "#;
+ let value = vec![Input {
+ source: "memory".to_string(),
+ reader: Box::new(first_flag_value.as_bytes()),
+ }];
+ let flags_bytes = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_ONLY,
+ false,
+ )
+ .unwrap();
+ let parsed_flags =
+ aconfig_protos::parsed_flags::try_from_binary_proto(&flags_bytes).unwrap();
+ assert_eq!(1, parsed_flags.parsed_flag.len());
+ let parsed_flag = parsed_flags.parsed_flag.first().unwrap();
+ assert_eq!(ProtoFlagState::DISABLED, parsed_flag.state());
+ assert_eq!(ProtoFlagPermission::READ_ONLY, parsed_flag.permission());
+ }
#[test]
fn test_parse_flags_override_fixed_read_only() {
@@ -682,6 +811,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -716,6 +846,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index e184efe..c390288 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -62,6 +62,12 @@
&commands::DEFAULT_FLAG_PERMISSION,
)),
)
+ .arg(
+ Arg::new("allow-read-write")
+ .long("allow-read-write")
+ .value_parser(clap::value_parser!(bool))
+ .default_value("true"),
+ )
.arg(Arg::new("cache").long("cache").required(true)),
)
.subcommand(
@@ -242,12 +248,15 @@
sub_matches,
"default-permission",
)?;
+ let allow_read_write = get_optional_arg::<bool>(sub_matches, "allow-read-write")
+ .expect("failed to parse allow-read-write");
let output = commands::parse_flags(
package,
container,
declarations,
values,
*default_permission,
+ *allow_read_write,
)
.context("failed to create cache")?;
let path = get_required_arg::<String>(sub_matches, "cache")?;
diff --git a/tools/aconfig/aconfig/src/storage/flag_info.rs b/tools/aconfig/aconfig/src/storage/flag_info.rs
index 5d565e8..0b5a67b 100644
--- a/tools/aconfig/aconfig/src/storage/flag_info.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_info.rs
@@ -73,7 +73,7 @@
pub fn create_test_flag_info_list_from_source() -> Result<FlagInfoList> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_info("mockup", &packages, DEFAULT_FILE_VERSION)
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index 8856eb6..ae5a16c 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -148,7 +148,7 @@
fn create_test_flag_table_from_source() -> Result<FlagTable> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_table("mockup", &packages, DEFAULT_FILE_VERSION)
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index 0dd5a9d..065b7e3 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -72,7 +72,7 @@
pub fn create_test_flag_value_list_from_source() -> Result<FlagValueList> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_value("mockup", &packages, DEFAULT_FILE_VERSION)
}
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index c7fd55a..ef1b4f6 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -22,6 +22,7 @@
use anyhow::Result;
use std::collections::{HashMap, HashSet};
+use crate::commands::compute_flags_fingerprint;
use crate::storage::{
flag_info::create_flag_info, flag_table::create_flag_table, flag_value::create_flag_value,
package_table::create_package_table,
@@ -59,7 +60,7 @@
}
}
-pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I) -> Vec<FlagPackage<'a>>
+pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I, version: u32) -> Vec<FlagPackage<'a>>
where
I: Iterator<Item = &'a ProtoParsedFlags>,
{
@@ -76,13 +77,18 @@
}
}
- // cacluate boolean flag start index for each package
+ // Calculate boolean flag start index for each package
let mut boolean_start_index = 0;
for p in packages.iter_mut() {
p.boolean_start_index = boolean_start_index;
boolean_start_index += p.boolean_flags.len() as u32;
- // TODO: b/316357686 - Calculate fingerprint and add to package.
+ if version > 2 {
+ let mut flag_names_vec =
+ p.flag_names.clone().into_iter().map(String::from).collect::<Vec<_>>();
+ let fingerprint = compute_flags_fingerprint(&mut flag_names_vec);
+ p.fingerprint = fingerprint;
+ }
}
packages
@@ -97,7 +103,7 @@
where
I: Iterator<Item = &'a ProtoParsedFlags>,
{
- let packages = group_flags_by_package(parsed_flags_vec_iter);
+ let packages = group_flags_by_package(parsed_flags_vec_iter, version);
match file {
StorageFileType::PackageMap => {
@@ -121,6 +127,8 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::Input;
@@ -163,6 +171,7 @@
reader: Box::new(value_content),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -173,7 +182,7 @@
#[test]
fn test_flag_package() {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
for pkg in packages.iter() {
let pkg_name = pkg.package_name;
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index e46607b..53daa7f 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -112,24 +112,59 @@
#[cfg(test)]
mod tests {
- use aconfig_storage_file::DEFAULT_FILE_VERSION;
+ use aconfig_storage_file::{DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION};
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
- pub fn create_test_package_table_from_source() -> Result<PackageTable> {
+ pub fn create_test_package_table_from_source(version: u32) -> Result<PackageTable> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
- create_package_table("mockup", &packages, DEFAULT_FILE_VERSION)
+ let packages = group_flags_by_package(caches.iter(), version);
+ create_package_table("mockup", &packages, version)
}
#[test]
// this test point locks down the table creation and each field
- fn test_table_contents() {
- let package_table = create_test_package_table_from_source();
- assert!(package_table.is_ok());
+ fn test_table_contents_default_version() {
+ let package_table_result = create_test_package_table_from_source(DEFAULT_FILE_VERSION);
+ assert!(package_table_result.is_ok());
+ let package_table = package_table_result.unwrap();
+
let expected_package_table =
aconfig_storage_file::test_utils::create_test_package_table(DEFAULT_FILE_VERSION);
- assert_eq!(package_table.unwrap(), expected_package_table);
+
+ assert_eq!(package_table.header, expected_package_table.header);
+ assert_eq!(package_table.buckets, expected_package_table.buckets);
+ for (node, expected_node) in
+ package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+ {
+ assert_eq!(node.package_name, expected_node.package_name);
+ assert_eq!(node.package_id, expected_node.package_id);
+ assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+ assert_eq!(node.next_offset, expected_node.next_offset);
+ }
+ }
+
+ #[test]
+ // this test point locks down the table creation and each field
+ fn test_table_contents_max_version() {
+ let package_table_result =
+ create_test_package_table_from_source(MAX_SUPPORTED_FILE_VERSION);
+ assert!(package_table_result.is_ok());
+ let package_table = package_table_result.unwrap();
+
+ let expected_package_table =
+ aconfig_storage_file::test_utils::create_test_package_table(MAX_SUPPORTED_FILE_VERSION);
+
+ assert_eq!(package_table.header, expected_package_table.header);
+ assert_eq!(package_table.buckets, expected_package_table.buckets);
+ for (node, expected_node) in
+ package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+ {
+ assert_eq!(node.package_name, expected_node.package_name);
+ assert_eq!(node.package_id, expected_node.package_id);
+ assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+ assert_eq!(node.next_offset, expected_node.next_offset);
+ }
}
}
diff --git a/tools/aconfig/aconfig/src/test.rs b/tools/aconfig/aconfig/src/test.rs
index a19b372..10da252 100644
--- a/tools/aconfig/aconfig/src/test.rs
+++ b/tools/aconfig/aconfig/src/test.rs
@@ -266,6 +266,7 @@
reader: Box::new(include_bytes!("../tests/read_only_test.values").as_slice()),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -290,6 +291,7 @@
},
],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -308,6 +310,7 @@
reader: Box::new(include_bytes!("../tests/third.values").as_slice()),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index cb52150..d782f81 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,41 +1,22 @@
package {package_name};
{{ -if not is_test_mode }}
{{ -if allow_instrumentation }}
-{{ if not library_exported- }}
+{{ if not library_exported- }}{#- only new storage for prod mode #}
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
-{{ -endif }}
-
{{ -if runtime_lookup_required }}
-import android.os.Binder;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-
-{{ -if not library_exported }}
import android.aconfig.storage.StorageInternalReader;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-{{ -endif }}
-
{{ -endif }}
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{
{{ -if runtime_lookup_required }}
-{{ -if not library_exported }}
- private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
private static volatile boolean isCached = false;
-{{ -endif }}
-{{ -for namespace_with_flags in namespace_flags }}
- private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
-{{ -endfor- }}
-
{{ for flag in flag_elements }}
{{ -if flag.is_read_write }}
private static boolean {flag.method_name} = {flag.default_value};
{{ -endif }}
{{ -endfor }}
-{{ if not library_exported }}
private void init() \{
StorageInternalReader reader = null;
boolean foundPackage = true;
@@ -53,9 +34,37 @@
{{ -endfor }}
isCached = true;
}
-{{ endif }}
-
-
+{{ -endif }}{#- end of runtime_lookup_required #}
+{{ -for flag in flag_elements }}
+ @Override
+ @com.android.aconfig.annotations.AconfigFlagAccessor
+ @UnsupportedAppUsage
+ public boolean {flag.method_name}() \{
+{{ -if flag.is_read_write }}
+ if (!isCached) \{
+ init();
+ }
+ return {flag.method_name};
+{{ -else }}
+ return {flag.default_value};
+{{ -endif }}
+ }
+{{ endfor }}
+}
+{{ -else- }}{#- device config for exproted mode #}
+import android.os.Binder;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+{{ -for namespace_with_flags in namespace_flags }}
+ private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
+{{ -endfor- }}
+{{ for flag in flag_elements }}
+{{ -if flag.is_read_write }}
+ private static boolean {flag.method_name} = {flag.default_value};
+{{ -endif }}
+{{ -endfor }}
{{ for namespace_with_flags in namespace_flags }}
private void load_overrides_{namespace_with_flags.namespace}() \{
final long ident = Binder.clearCallingIdentity();
@@ -84,40 +93,17 @@
{namespace_with_flags.namespace}_is_cached = true;
}
{{ endfor- }}
-
-{{ -endif }}{#- end of runtime_lookup_required #}
{{ -for flag in flag_elements }}
@Override
-{{ -if not library_exported }}
- @com.android.aconfig.annotations.AconfigFlagAccessor
- @UnsupportedAppUsage
-{{ -endif }}
public boolean {flag.method_name}() \{
-{{ -if not library_exported }}
-{{ -if flag.is_read_write }}
- if (isReadFromNew) \{
- if (!isCached) \{
- init();
- }
- } else \{
- if (!{flag.device_config_namespace}_is_cached) \{
- load_overrides_{flag.device_config_namespace}();
- }
- }
- return {flag.method_name};
-{{ -else }}
- return {flag.default_value};
-{{ -endif }}
-{{ else }}
if (!{flag.device_config_namespace}_is_cached) \{
load_overrides_{flag.device_config_namespace}();
}
return {flag.method_name};
-{{ -endif }}
}
{{ endfor }}
}
-
+{{ -endif- }} {#- end exported mode #}
{{ else }} {#- else for allow_instrumentation is not enabled #}
{{ if not library_exported- }}
// TODO(b/303773055): Remove the annotation after access issue is resolved.
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index df3b10d..9be59e0 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -76,17 +76,8 @@
: boolean_start_index_()
{{ -endif }}
, flag_value_file_(nullptr)
- , read_from_new_storage_(false)
, package_exists_in_storage_(true) \{
- if (access("/metadata/aconfig/boot/enable_only_new_storage", F_OK) == 0) \{
- read_from_new_storage_ = true;
- }
-
- if (!read_from_new_storage_) \{
- return;
- }
-
auto package_map_file = aconfig_storage::get_mapped_file(
"{container}",
aconfig_storage::StorageFileType::package_map);
@@ -137,26 +128,19 @@
{{ -if item.readwrite }}
if (cache_[{item.readwrite_idx}] == -1) \{
{{ if allow_instrumentation- }}
- if (read_from_new_storage_) \{
- if (!package_exists_in_storage_) \{
- return {item.default_value};
- }
-
- auto value = aconfig_storage::get_boolean_flag_value(
- *flag_value_file_,
- boolean_start_index_ + {item.flag_offset});
-
- if (!value.ok()) \{
- ALOGE("error: failed to read flag value: %s", value.error().c_str());
- }
-
- cache_[{item.readwrite_idx}] = *value;
- } else \{
- cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
- "aconfig_flags.{item.device_config_namespace}",
- "{item.device_config_flag}",
- "{item.default_value}") == "true";
+ if (!package_exists_in_storage_) \{
+ return {item.default_value};
}
+
+ auto value = aconfig_storage::get_boolean_flag_value(
+ *flag_value_file_,
+ boolean_start_index_ + {item.flag_offset});
+
+ if (!value.ok()) \{
+ ALOGE("error: failed to read flag value: %s", value.error().c_str());
+ }
+
+ cache_[{item.readwrite_idx}] = *value;
{{ -else- }}
cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.{item.device_config_namespace}",
@@ -183,8 +167,6 @@
std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
- bool read_from_new_storage_;
-
bool package_exists_in_storage_;
{{ -endif }}
{{ -endif }}
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index d0079d4..e9e1032 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -10,10 +10,6 @@
{{ if has_readwrite- }}
{{ if allow_instrumentation }}
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe \{
- Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe \{
get_mapped_storage_file("{container}", StorageFileType::PackageMap)
.and_then(|package_map| get_package_read_context(&package_map, "{package}"))
@@ -31,48 +27,41 @@
{{ if allow_instrumentation }}
static CACHED_{flag.name}: LazyLock<bool> = LazyLock::new(|| \{
- if *READ_FROM_NEW_STORAGE \{
- // This will be called multiple times. Subsequent calls after the first are noops.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("aconfig_rust_codegen")
- .with_max_level(LevelFilter::Info));
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device("aconfig_rust_codegen")
+ .with_max_level(LevelFilter::Info));
- let flag_value_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 => \{
- log!(Level::Error, "no context found for package {package}");
- Err(format!("failed to flag package {package}"))
- }
+ let flag_value_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 => \{
+ log!(Level::Error, "no context found for package {package}");
+ Err(format!("failed to flag package {package}"))
}
- })
- });
+ }
+ })
+ });
- match flag_value_result \{
- Ok(flag_value) => \{
- return flag_value;
- },
- Err(err) => \{
- log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
- return {flag.default_value};
- }
+ match flag_value_result \{
+ Ok(flag_value) => \{
+ return flag_value;
+ },
+ Err(err) => \{
+ log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
+ return {flag.default_value};
}
- } else \{
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.{flag.device_config_namespace}",
- "{flag.device_config_flag}",
- "{flag.default_value}") == "true"
}
});
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 55780ed..7c603df 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -46,14 +46,22 @@
let first_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_2"),
package_id: 1,
- fingerprint: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 4431940502274857964u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 3,
next_offset: None,
};
let second_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_1"),
package_id: 0,
- fingerprint: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 15248948510590158086u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 0,
next_offset: match version {
1 => Some(159),
@@ -64,7 +72,11 @@
let third_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_4"),
package_id: 2,
- fingerprint: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 16233229917711622375u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 6,
next_offset: None,
};
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
index b1c7ee7..324c55d 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
@@ -39,6 +39,8 @@
/** Error code indicating that there was an error reading the Aconfig Storage file. */
public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
private final int mErrorCode;
/**
@@ -126,6 +128,8 @@
return "ERROR_CONTAINER_NOT_FOUND";
case ERROR_CANNOT_READ_STORAGE_FILE:
return "ERROR_CANNOT_READ_STORAGE_FILE";
+ case ERROR_FILE_FINGERPRINT_MISMATCH:
+ return "ERROR_FILE_FINGERPRINT_MISMATCH";
default:
return "<Unknown error code " + mErrorCode + ">";
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
index b0b1b9b..c354873 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
@@ -42,4 +42,20 @@
return null;
}
}
+
+ @Override
+ public String toString() {
+ switch (type) {
+ case 0:
+ return "PACKAGE_MAP";
+ case 1:
+ return "FLAG_MAP";
+ case 2:
+ return "FLAG_VAL";
+ case 3:
+ return "FLAG_INFO";
+ default:
+ return "unrecognized type";
+ }
+ }
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index 8306cc6..f1a4e26 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -26,7 +26,10 @@
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** @hide */
public class StorageFileProvider {
@@ -52,13 +55,20 @@
}
/** @hide */
- public List<Path> listPackageMapFiles() {
- List<Path> result = new ArrayList<>();
+ public List<String> listContainers(String[] excludes) {
+ List<String> result = new ArrayList<>();
+ Set<String> set = new HashSet<>(Arrays.asList(excludes));
+
try {
DirectoryStream<Path> stream =
Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
for (Path entry : stream) {
- result.add(entry);
+ String fileName = entry.getFileName().toString();
+ String container =
+ fileName.substring(0, fileName.length() - PMAP_FILE_EXT.length());
+ if (!set.contains(container)) {
+ result.add(container);
+ }
}
} catch (NoSuchFileException e) {
return result;
@@ -77,22 +87,23 @@
/** @hide */
public FlagTable getFlagTable(String container) {
- return FlagTable.fromBytes(mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT)));
+ return FlagTable.fromBytes(
+ mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT), FileType.FLAG_MAP));
}
/** @hide */
public FlagValueList getFlagValueList(String container) {
return FlagValueList.fromBytes(
- mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT)));
+ mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
}
/** @hide */
public static PackageTable getPackageTable(Path path) {
- return PackageTable.fromBytes(mapStorageFile(path));
+ return PackageTable.fromBytes(mapStorageFile(path, FileType.PACKAGE_MAP));
}
// Map a storage file given file path
- private static MappedByteBuffer mapStorageFile(Path file) {
+ private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
FileChannel channel = null;
try {
channel = FileChannel.open(file, StandardOpenOption.READ);
@@ -100,7 +111,7 @@
} catch (Exception e) {
throw new AconfigStorageException(
AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
- String.format("Fail to mmap storage file %s", file),
+ String.format("Fail to mmap storage %s file %s", type.toString(), file),
e);
} finally {
quietlyDispose(channel);
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index 4d7ab2a..5906d8b 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -116,5 +116,9 @@
assertTrue(node1.hasPackageFingerprint());
assertTrue(node2.hasPackageFingerprint());
assertTrue(node4.hasPackageFingerprint());
+
+ assertEquals(-3197795563119393530L, node1.getPackageFingerprint());
+ assertEquals(4431940502274857964L, node2.getPackageFingerprint());
+ assertEquals(-2213514155997929241L, node4.getPackageFingerprint());
}
}
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
index 4e90e6c..a820970 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -29,7 +29,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@@ -37,15 +36,20 @@
public class StorageFileProviderTest {
@Test
- public void testListpackageMapFiles() throws Exception {
+ public void testlistContainers() throws Exception {
StorageFileProvider p =
new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- List<Path> file = p.listPackageMapFiles();
- assertEquals(2, file.size());
+ String[] excludes = {};
+ List<String> containers = p.listContainers(excludes);
+ assertEquals(2, containers.size());
+
+ excludes = new String[] {"mock.v1"};
+ containers = p.listContainers(excludes);
+ assertEquals(1, containers.size());
p = new StorageFileProvider("fake/path/", "fake/path/");
- file = p.listPackageMapFiles();
- assertTrue(file.isEmpty());
+ containers = p.listContainers(excludes);
+ assertTrue(containers.isEmpty());
}
@Test
@@ -56,8 +60,7 @@
assertNotNull(pt);
pt =
StorageFileProvider.getPackageTable(
- Paths.get(
- TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
+ Paths.get(TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
assertNotNull(pt);
FlagTable f = p.getFlagTable("mock.v1");
assertNotNull(f);
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 3238d79..09daeea 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,12 +154,13 @@
java_library {
name: "aconfig_storage_reader_java",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
+ "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
],
libs: [
"unsupportedappusage",
"strict_mode_stub",
+ "aconfig_storage_stub",
],
static_libs: [
"aconfig_storage_file_java",
@@ -176,8 +177,8 @@
java_library {
name: "aconfig_storage_reader_java_none",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
+ "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
],
libs: [
"unsupportedappusage-sdk-none",
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
deleted file mode 100644
index 6bf4e05..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.aconfig.storage;
-
-import android.os.StrictMode;
-
-import java.nio.file.Path;
-
-/** @hide */
-public class AconfigPackageImpl {
- private FlagTable mFlagTable;
- private FlagValueList mFlagValueList;
- private PackageTable.Node mPNode;
- private final int mPackageId;
- private final int mBooleanStartIndex;
-
- private AconfigPackageImpl(
- FlagTable flagTable,
- FlagValueList flagValueList,
- int packageId,
- int booleanStartIndex) {
- this.mFlagTable = flagTable;
- this.mFlagValueList = flagValueList;
- this.mPackageId = packageId;
- this.mBooleanStartIndex = booleanStartIndex;
- }
-
- public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- PackageTable.Node pNode = null;
- try {
- // First try to find the package in the "system" container.
- pNode = fileProvider.getPackageTable("system").get(packageName);
- } catch (Exception e) {
- //
- }
- try {
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable("system"),
- fileProvider.getFlagValueList("system"),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
-
- // If not found in "system", search all package map files.
- for (Path p : fileProvider.listPackageMapFiles()) {
- PackageTable pTable = fileProvider.getPackageTable(p);
- pNode = pTable.get(packageName);
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable(pTable.getHeader().getContainer()),
- fileProvider.getFlagValueList(pTable.getHeader().getContainer()),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- // Package not found.
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "Package " + packageName + " not found.");
- }
-
- public static AconfigPackageImpl load(
- String container, String packageName, StorageFileProvider fileProvider) {
-
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- try {
- PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable(container),
- fileProvider.getFlagValueList(container),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
-
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "package "
- + packageName
- + " in container "
- + container
- + " cannot be found on the device");
- }
-
- public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
- FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
- if (fNode == null) return defaultValue;
- return mFlagValueList.getBoolean(fNode.getFlagIndex() + mBooleanStartIndex);
- }
-
- public boolean getBooleanFlagValue(int index) {
- return mFlagValueList.getBoolean(index + mBooleanStartIndex);
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..83310be
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,264 @@
+/*
+ * 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.flagging;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.StrictMode;
+
+/**
+ * An {@code aconfig} package containing the enabled state of its flags.
+ *
+ * <p><strong>Note: this is intended only to be used by generated code. To determine if a given flag
+ * is enabled in app code, the generated android flags should be used.</strong>
+ *
+ * <p>This class is not part of the public API and should be used by Acnofig Flag internally </b> It
+ * is intended for internal use only and will be changed or removed without notice.
+ *
+ * <p>This class is used to read the flag from Aconfig Package.Each instance of this class will
+ * cache information related to one package. To read flags from a different package, a new instance
+ * of this class should be {@link #load loaded}.
+ *
+ * @hide
+ */
+public class PlatformAconfigPackageInternal {
+
+ private final FlagTable mFlagTable;
+ private final FlagValueList mFlagValueList;
+ private final int mPackageId;
+ private final int mPackageBooleanStartOffset;
+ private final AconfigStorageException mException;
+
+ private PlatformAconfigPackageInternal(
+ FlagValueList flagValueList,
+ FlagTable flagTable,
+ int packageBooleanStartOffset,
+ int packageId,
+ AconfigStorageException exception) {
+ this.mFlagValueList = flagValueList;
+ this.mFlagTable = flagTable;
+ this.mPackageBooleanStartOffset = packageBooleanStartOffset;
+ this.mPackageId = packageId;
+ this.mException = exception;
+ }
+
+ /**
+ * Loads an Aconfig Package from platform Aconfig Storage.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method loads the specified Aconfig Package from the given container.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package to load.
+ * @return An instance of {@link PlatformAconfigPackageInternal}
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(String container, String packageName) {
+ return load(container, packageName, StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Loads an Aconfig package from the specified container and verifies its fingerprint.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package.
+ * @param packageFingerprint The expected fingerprint of the package.
+ * @return An instance of {@link PlatformAconfigPackageInternal} representing the loaded
+ * package.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ return load(
+ container,
+ packageName,
+ packageFingerprint,
+ StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container,
+ String packageName,
+ long packageFingerprint,
+ StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ if (pNode.hasPackageFingerprint()
+ && packageFingerprint != pNode.getPackageFingerprint()) {
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ new AconfigStorageException(
+ AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ "The fingerprint provided for the Aconfig package "
+ + packageName
+ + " in container "
+ + container
+ + " does not match"
+ + " the fingerprint of the package found on the device."));
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ null,
+ pNode.getBooleanStartIndex(),
+ 0,
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its index.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * index. The index is generated at build time and may vary between builds.
+ *
+ * <p>To ensure you are using the correct index, verify that the package's fingerprint matches
+ * the expected fingerprint before calling this method. If the fingerprints do not match, use
+ * {@link #getBooleanFlagValue(String, boolean)} instead.
+ *
+ * @param index The index of the flag within the package.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(int index) {
+ return mFlagValueList.getBoolean(index + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its name.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * name.
+ *
+ * @param flagName The name of the flag.
+ * @param defaultValue The default value to return if the flag is not found.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
+ if (fNode == null) {
+ return defaultValue;
+ }
+ return mFlagValueList.getBoolean(fNode.getFlagIndex() + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Returns any exception that occurred during the loading of the Aconfig package.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * @return The exception that occurred, or {@code null} if no exception occurred.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public Exception getException() {
+ return mException;
+ }
+
+ /**
+ * Creates a new {@link PlatformAconfigPackageInternal} instance with an {@link
+ * AconfigStorageException}.
+ *
+ * @param errorCode The error code for the exception.
+ * @param message The error message for the exception.
+ * @return A new {@link PlatformAconfigPackageInternal} instance with the specified exception.
+ */
+ private static PlatformAconfigPackageInternal createExceptionInstance(
+ int errorCode, String message) {
+ return new PlatformAconfigPackageInternal(
+ null, null, 0, 0, new AconfigStorageException(errorCode, message));
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
similarity index 95%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
index 7ffa18c..ee50060 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
@@ -26,7 +26,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="aconfig_storage_read_api.test.java.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_functional.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" />
@@ -45,7 +45,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="package" value="android.aconfig_storage.test" />
+ <option name="package" value="android.aconfig.storage.test" />
<option name="runtime-hint" value="1m" />
</test>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
similarity index 69%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
index 861b9b5..e528dd5 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
@@ -17,15 +17,15 @@
<configuration description="Test aconfig storage java tests">
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="aconfig_storage_package.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_unit.apk" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
- <option name="push" value="package_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
- <option name="push" value="flag_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
- <option name="push" value="flag_v1.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
- <option name="push" value="flag_v1.info->/data/local/tmp/aconfig_storage_package/testdata/mockup.info" />
- <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_package/testdata/" />
+ <option name="push" value="package_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.package.map" />
+ <option name="push" value="flag_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.flag.map" />
+ <option name="push" value="flag_v2.val->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.val" />
+ <option name="push" value="flag_v2.info->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.info" />
+ <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_read_unit/testdata/" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.aconfig.storage.test" />
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index 6b8942b..fb2fc77 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -48,3 +48,53 @@
"general-tests",
],
}
+
+android_test {
+ name: "aconfig_storage_read_functional",
+ srcs: [
+ "functional/srcs/**/*.java",
+ ],
+ static_libs: [
+ "aconfig_device_paths_java",
+ "aconfig_storage_file_java",
+ "aconfig_storage_reader_java",
+ "androidx.test.rules",
+ "libaconfig_storage_read_api_java",
+ "junit",
+ ],
+ jni_libs: [
+ "libaconfig_storage_read_api_rust_jni",
+ ],
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadFunctionalTest.xml",
+ team: "trendy_team_android_core_experiments",
+}
+
+android_test {
+ name: "aconfig_storage_read_unit",
+ team: "trendy_team_android_core_experiments",
+ srcs: [
+ "unit/srcs/**/*.java",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "aconfig_storage_reader_java",
+ ],
+ sdk_version: "test_current",
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadUnitTest.xml",
+ jarjar_rules: "jarjar.txt",
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
index 191741e..6dd1bce 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
@@ -267,4 +267,4 @@
assertEquals(rVal, jVal);
}
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..15cfc3b
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.aconfig.storage.test;
+
+import static android.aconfig.nano.Aconfig.ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ private static final Set<String> PLATFORM_CONTAINERS = Set.of("system", "vendor", "product");
+
+ @Test
+ public void testAconfigPackageInternal_load() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(flagName, !rVal);
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testPlatformAconfigPackageInternal_load_with_fingerprint() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ long fingerprint = pNode.getPackageFingerprint();
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName, fingerprint);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(fNode.getFlagIndex());
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testAconfigPackage_load_withError() throws IOException {
+ // container not found fake_container
+ PlatformAconfigPackageInternal aPackage =
+ PlatformAconfigPackageInternal.load("fake_container", "fake_package", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) aPackage.getException()).getErrorCode());
+
+ // package not found
+ aPackage = PlatformAconfigPackageInternal.load("system", "fake_container", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) aPackage.getException()).getErrorCode());
+
+ // fingerprint doesn't match
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ parsed_flag flag = flags.get(0);
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ boolean value = flag.state == ENABLED;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+
+ if (pNode.hasPackageFingerprint()) {
+ long fingerprint = pNode.getPackageFingerprint();
+ aPackage = PlatformAconfigPackageInternal.load(container, packageName, fingerprint + 1);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, ((AconfigStorageException) aPackage.getException()).getErrorCode());
+ assertEquals(aPackage.getBooleanFlagValue(flag.name, !value), value);
+ }
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
index 3a1bba0..8a8f054 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
@@ -42,4 +42,4 @@
assertFalse(reader.getBooleanFlagValue(0));
assertTrue(reader.getBooleanFlagValue(1));
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
similarity index 91%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
rename to tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
index 24952ec..49250d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
+++ b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
@@ -15,3 +15,5 @@
rule android.aconfig.storage.PackageTable$* android.aconfig.storage.test.PackageTable$@1
rule android.aconfig.storage.FlagValueList$* android.aconfig.storage.test.FlagValueList@1
rule android.aconfig.storage.SipHasher13$* android.aconfig.storage.test.SipHasher13@1
+
+rule android.os.flagging.PlatformAconfigPackageInternal android.aconfig.storage.test.PlatformAconfigPackageInternal
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
deleted file mode 100644
index 80c0994..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.aconfig.storage.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.AconfigPackageImpl;
-import android.aconfig.storage.AconfigStorageException;
-import android.aconfig.storage.StorageFileProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AconfigPackageImplTest {
-
- private StorageFileProvider pr;
-
- @Before
- public void setup() {
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- }
-
- @Test
- public void testLoad_onlyPackageName() throws Exception {
- AconfigPackageImpl p = AconfigPackageImpl.load("com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_groupNameFingerprint() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_error() throws Exception {
- AconfigPackageImpl p;
- // cannot find package
- AconfigStorageException e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_10", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find package
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("com.android.aconfig.storage.test_10", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find container
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- null, "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "test", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
-
- // new storage doesn't exist
- pr = new StorageFileProvider("fake/path/", "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("fake_package", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
-
- // file read issue
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- }
-
- @Test
- public void testGetBooleanFlagValue_flagName() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue("disabled_rw", true));
- assertTrue(p.getBooleanFlagValue("enabled_ro", false));
- assertTrue(p.getBooleanFlagValue("enabled_rw", false));
- assertFalse(p.getBooleanFlagValue("fake", false));
- }
-
- @Test
- public void testGetBooleanFlagValue_index() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue(0));
- assertTrue(p.getBooleanFlagValue(1));
- assertTrue(p.getBooleanFlagValue(2));
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
deleted file mode 100644
index 0de34a6..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-android_test {
- name: "aconfig_storage_read_api.test.java",
- srcs: ["./**/*.java"],
- static_libs: [
- "aconfig_device_paths_java",
- "aconfig_storage_file_java",
- "aconfig_storage_reader_java",
- "androidx.test.rules",
- "libaconfig_storage_read_api_java",
- "junit",
- ],
- jni_libs: [
- "libaconfig_storage_read_api_rust_jni",
- ],
- data: [
- ":read_api_test_storage_files",
- ],
- platform_apis: true,
- certificate: "platform",
- test_suites: [
- "general-tests",
- ],
- team: "trendy_team_android_core_experiments",
-}
-
-android_test {
- name: "aconfig_storage_package",
- team: "trendy_team_android_core_experiments",
- srcs: [
- "AconfigPackageImplTest.java",
- "TestDataUtils.java",
- ],
- static_libs: [
- "androidx.test.runner",
- "junit",
- "aconfig_storage_reader_java",
- ],
- test_config: "AndroidStorageJaveTest.xml",
- manifest: "AndroidPackageTestManifest.xml",
- sdk_version: "test_current",
- data: [
- ":read_api_test_storage_files",
- ],
- test_suites: [
- "general-tests",
- ],
- jarjar_rules: "jarjar.txt",
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
deleted file mode 100644
index 78bfb37..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.aconfig_storage.test">
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.aconfig_storage.test" />
-
-</manifest>
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
deleted file mode 100644
index d5cddc7..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.aconfig.storage.test;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-public final class TestDataUtils {
- public static final String TEST_PACKAGE_MAP_PATH = "mockup.package.map";
- public static final String TEST_FLAG_MAP_PATH = "mockup.flag.map";
- public static final String TEST_FLAG_VAL_PATH = "mockup.val";
- public static final String TEST_FLAG_INFO_PATH = "mockup.info";
-
- public static final String TESTDATA_PATH =
- "/data/local/tmp/aconfig_storage_package/testdata/";
-
- public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
- }
-
- public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
- }
-
- private static ByteBuffer readFile(String fileName) throws Exception {
- InputStream input = new FileInputStream(fileName);
- return ByteBuffer.wrap(input.readAllBytes());
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..392f644
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.aconfig.storage.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ public static final String TESTDATA_PATH =
+ "/data/local/tmp/aconfig_storage_read_unit/testdata/";
+
+ private StorageFileProvider pr;
+
+ @Before
+ public void setup() {
+ pr = new StorageFileProvider(TESTDATA_PATH, TESTDATA_PATH);
+ }
+
+ @Test
+ public void testLoad_container_package() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_error() throws Exception {
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // cannot find container
+ p = PlatformAconfigPackageInternal.load(null, "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ p = PlatformAconfigPackageInternal.load("test", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint() throws Exception {
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint_error() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", fingerprint, pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // cannot find container
+ p =
+ PlatformAconfigPackageInternal.load(
+ null, "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ p =
+ PlatformAconfigPackageInternal.load(
+ "test", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ // fingerprint doesn't match
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint + 1, pr);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_flagName() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertFalse(p.getBooleanFlagValue("disabled_rw", true));
+ assertTrue(p.getBooleanFlagValue("enabled_ro", false));
+ assertTrue(p.getBooleanFlagValue("enabled_rw", false));
+ assertFalse(p.getBooleanFlagValue("fake", false));
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_index() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertFalse(p.getBooleanFlagValue(0));
+ assertTrue(p.getBooleanFlagValue(1));
+ assertTrue(p.getBooleanFlagValue(2));
+ }
+}
diff --git a/tools/aconfig/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 1f17e6b..4cd5070 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -32,3 +32,13 @@
host_supported: true,
is_stubs_module: true,
}
+
+java_library {
+ name: "aconfig_storage_stub",
+ srcs: [
+ "src/android/os/flagging/**/*.java",
+ ],
+ sdk_version: "core_current",
+ host_supported: true,
+ is_stubs_module: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
new file mode 100644
index 0000000..bfec98c
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
@@ -0,0 +1,61 @@
+/*
+ * 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.flagging;
+
+public class AconfigStorageReadException extends RuntimeException {
+
+ /** Generic error code indicating an unspecified Aconfig Storage error. */
+ public static final int ERROR_GENERIC = 0;
+
+ /** Error code indicating that the Aconfig Storage system is not found on the device. */
+ public static final int ERROR_STORAGE_SYSTEM_NOT_FOUND = 1;
+
+ /** Error code indicating that the requested configuration package is not found. */
+ public static final int ERROR_PACKAGE_NOT_FOUND = 2;
+
+ /** Error code indicating that the specified container is not found. */
+ public static final int ERROR_CONTAINER_NOT_FOUND = 3;
+
+ /** Error code indicating that there was an error reading the Aconfig Storage file. */
+ public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
+ public AconfigStorageReadException(int errorCode, String msg) {
+ super(msg);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, String msg, Throwable cause) {
+ super(msg, cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, Throwable cause) {
+ super(cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public int getErrorCode() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ @Override
+ public String getMessage() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/edit_monitor/daemon_manager.py b/tools/edit_monitor/daemon_manager.py
index da85c11..22782f7 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -33,7 +33,7 @@
DEFAULT_PROCESS_TERMINATION_TIMEOUT_SECONDS = 5
DEFAULT_MONITOR_INTERVAL_SECONDS = 5
-DEFAULT_MEMORY_USAGE_THRESHOLD = 3 * 1024 # 3GB
+DEFAULT_MEMORY_USAGE_THRESHOLD = 0.02 # 2% of total memory
DEFAULT_CPU_USAGE_THRESHOLD = 200
DEFAULT_REBOOT_TIMEOUT_SECONDS = 60 * 60 * 24
BLOCK_SIGN_FILE = "edit_monitor_block_sign"
@@ -70,6 +70,9 @@
self.max_memory_usage = 0
self.max_cpu_usage = 0
+ self.total_memory_size = os.sysconf("SC_PAGE_SIZE") * os.sysconf(
+ "SC_PHYS_PAGES"
+ )
pid_file_dir = pathlib.Path(tempfile.gettempdir()).joinpath("edit_monitor")
pid_file_dir.mkdir(parents=True, exist_ok=True)
@@ -84,7 +87,7 @@
"edit_monitor",
self.user_name,
"ENABLE_ANDROID_EDIT_MONITOR",
- 10,
+ 50,
):
logging.warning("Edit monitor is disabled, exiting...")
return
@@ -142,10 +145,20 @@
logging.warning("Failed to monitor daemon process with error: %s", e)
if self.max_memory_usage >= memory_threshold:
- self._handle_resource_exhausted_error("memory")
+ self._send_error_event_to_clearcut(
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE
+ )
+ logging.error(
+ "Daemon process is consuming too much memory, rebooting...")
+ self.reboot()
if self.max_cpu_usage >= cpu_threshold:
- self._handle_resource_exhausted_error("cpu")
+ self._send_error_event_to_clearcut(
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE
+ )
+ logging.error(
+ "Daemon process is consuming too much cpu, killing...")
+ self._terminate_process(self.daemon_process.pid)
logging.info(
"Daemon process %d terminated. Max memory usage: %f, Max cpu"
@@ -345,7 +358,13 @@
stat_data = f.readline().split()
# RSS is the 24th field in /proc/[pid]/stat
rss_pages = int(stat_data[23])
- return rss_pages * 4 / 1024 # Covert to MB
+ process_memory = rss_pages * 4 * 1024 # Convert to bytes
+
+ return (
+ process_memory / self.total_memory_size
+ if self.total_memory_size
+ else 0.0
+ )
def _get_process_cpu_percent(self, pid: int, interval: int = 1) -> float:
total_start_time = self._get_total_cpu_time(pid)
@@ -386,20 +405,6 @@
return pids
- def _handle_resource_exhausted_error(self, resource_type:str):
- if resource_type == "memory":
- self._send_error_event_to_clearcut(
- edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE
- )
- else:
- self._send_error_event_to_clearcut(
- edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE
- )
- logging.error(
- "Daemon process is consuming too much %s, killing...", resource_type
- ),
- self._terminate_process(self.daemon_process.pid)
-
def _send_error_event_to_clearcut(self, error_type):
edit_monitor_error_event_proto = edit_event_pb2.EditEvent(
user_name=self.user_name,
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index 12aaab3..350739d 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -202,23 +202,31 @@
fake_cclient, edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
)
- def test_monitor_daemon_subprocess_killed_high_memory_usage(self):
+ @mock.patch('os.execv')
+ def test_monitor_reboot_with_high_memory_usage(self, mock_execv):
fake_cclient = FakeClearcutClient()
+ binary_file = tempfile.NamedTemporaryFile(
+ dir=self.working_dir.name, delete=False
+ )
+
dm = daemon_manager.DaemonManager(
- TEST_BINARY_FILE,
+ binary_file.name,
daemon_target=memory_consume_daemon_target,
daemon_args=(2,),
cclient=fake_cclient,
)
+ # set the fake total_memory_size
+ dm.total_memory_size = 100 * 1024 *1024
dm.start()
- dm.monitor_daemon(interval=1, memory_threshold=2)
+ dm.monitor_daemon(interval=1)
- self.assertTrue(dm.max_memory_usage >= 2)
+ self.assertTrue(dm.max_memory_usage >= 0.02)
self.assert_no_subprocess_running()
self._assert_error_event_logged(
fake_cclient,
edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE,
)
+ mock_execv.assert_called_once()
def test_monitor_daemon_subprocess_killed_high_cpu_usage(self):
fake_cclient = FakeClearcutClient()
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index c25ff27..30a6acc 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -1100,7 +1100,7 @@
vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(avb_custom_partitions)
vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
- if vbmeta_system:
+ if vbmeta_system and set(vbmeta_system.split()).intersection(partitions):
banner("vbmeta_system")
partitions["vbmeta_system"] = AddVBMeta(
output_zip, partitions, "vbmeta_system", vbmeta_system.split())
@@ -1110,7 +1110,7 @@
vbmeta_partitions.append("vbmeta_system")
vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
- if vbmeta_vendor:
+ if vbmeta_vendor and set(vbmeta_vendor.split()).intersection(partitions):
banner("vbmeta_vendor")
partitions["vbmeta_vendor"] = AddVBMeta(
output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
@@ -1137,7 +1137,7 @@
if item not in included_partitions]
vbmeta_partitions.append(partition_name)
- if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
+ if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true" and set(vbmeta_partitions).intersection(partitions):
banner("vbmeta")
AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)