Merge "Support aconfig dump --dedup" into main
diff --git a/core/Makefile b/core/Makefile
index b93c321..7d7457e 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -2122,6 +2122,7 @@
$(if $(BOARD_$(_var)IMAGE_EXTFS_INODE_COUNT),$(hide) echo "$(1)_extfs_inode_count=$(BOARD_$(_var)IMAGE_EXTFS_INODE_COUNT)" >> $(2))
$(if $(BOARD_$(_var)IMAGE_EXTFS_RSV_PCT),$(hide) echo "$(1)_extfs_rsv_pct=$(BOARD_$(_var)IMAGE_EXTFS_RSV_PCT)" >> $(2))
$(if $(BOARD_$(_var)IMAGE_F2FS_SLOAD_COMPRESS_FLAGS),$(hide) echo "$(1)_f2fs_sldc_flags=$(BOARD_$(_var)IMAGE_F2FS_SLOAD_COMPRESS_FLAGS)" >> $(2))
+$(if $(BOARD_$(_var)IMAGE_F2FS_BLOCKSIZE),$(hide) echo "$(1)_f2fs_blocksize=$(BOARD_$(_var)IMAGE_F2FS_BLOCKSIZE)" >> $(2))
$(if $(BOARD_$(_var)IMAGE_FILE_SYSTEM_COMPRESS),$(hide) echo "$(1)_f2fs_compress=$(BOARD_$(_var)IMAGE_FILE_SYSTEM_COMPRESS)" >> $(2))
$(if $(BOARD_$(_var)IMAGE_FILE_SYSTEM_TYPE),$(hide) echo "$(1)_fs_type=$(BOARD_$(_var)IMAGE_FILE_SYSTEM_TYPE)" >> $(2))
$(if $(BOARD_$(_var)IMAGE_JOURNAL_SIZE),$(hide) echo "$(1)_journal_size=$(BOARD_$(_var)IMAGE_JOURNAL_SIZE)" >> $(2))
@@ -2212,6 +2213,7 @@
$(if $(BOARD_EROFS_SHARE_DUP_BLOCKS),$(hide) echo "erofs_share_dup_blocks=$(BOARD_EROFS_SHARE_DUP_BLOCKS)" >> $(1))
$(if $(BOARD_EROFS_USE_LEGACY_COMPRESSION),$(hide) echo "erofs_use_legacy_compression=$(BOARD_EROFS_USE_LEGACY_COMPRESSION)" >> $(1))
$(if $(BOARD_EXT4_SHARE_DUP_BLOCKS),$(hide) echo "ext4_share_dup_blocks=$(BOARD_EXT4_SHARE_DUP_BLOCKS)" >> $(1))
+$(if $(BOARD_F2FS_BLOCKSIZE),$(hide) echo "f2fs_blocksize=$(BOARD_F2FS_BLOCKSIZE)" >> $(1))
$(if $(BOARD_FLASH_LOGICAL_BLOCK_SIZE), $(hide) echo "flash_logical_block_size=$(BOARD_FLASH_LOGICAL_BLOCK_SIZE)" >> $(1))
$(if $(BOARD_FLASH_ERASE_BLOCK_SIZE), $(hide) echo "flash_erase_block_size=$(BOARD_FLASH_ERASE_BLOCK_SIZE)" >> $(1))
$(if $(filter eng, $(TARGET_BUILD_VARIANT)),$(hide) echo "verity_disable=true" >> $(1))
@@ -3779,7 +3781,7 @@
ALL_DEFAULT_INSTALLED_MODULES += $(_vendor_dlkm_lib_modules_symlink)
endif
-# Install vendor/etc/linker.config.pb with PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS and STUB_LIBRARIES
+# Install vendor/etc/linker.config.pb with PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS and SOONG_STUB_VENDOR_LIBRARIES
vendor_linker_config_file := $(TARGET_OUT_VENDOR)/etc/linker.config.pb
$(vendor_linker_config_file): private_linker_config_fragments := $(PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS)
$(vendor_linker_config_file): $(INTERNAL_VENDORIMAGE_FILES) $(PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS) | $(HOST_OUT_EXECUTABLES)/conv_linker_config
@@ -3790,7 +3792,7 @@
--source $(call normalize-path-list,$(private_linker_config_fragments)) \
--output $@
$(HOST_OUT_EXECUTABLES)/conv_linker_config systemprovide --source $@ \
- --output $@ --value "$(STUB_LIBRARIES)" --system "$(TARGET_OUT_VENDOR)"
+ --output $@ --value "$(SOONG_STUB_VENDOR_LIBRARIES)" --system "$(TARGET_OUT_VENDOR)"
$(call define declare-0p-target,$(vendor_linker_config_file),)
INTERNAL_VENDORIMAGE_FILES += $(vendor_linker_config_file)
ALL_DEFAULT_INSTALLED_MODULES += $(vendor_linker_config_file)
@@ -4598,6 +4600,12 @@
--prop com.android.build.pvmfw.security_patch:$(PVMFW_SECURITY_PATCH)
endif
+# Append avbpubkey of microdroid-vendor partition into vendor_boot partition.
+ifdef MICRODROID_VENDOR_AVBKEY
+BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS += \
+ --prop_from_file com.android.build.microdroid-vendor.avbpubkey:$(MICRODROID_VENDOR_AVBKEY)
+endif
+
BOOT_FOOTER_ARGS := BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS
INIT_BOOT_FOOTER_ARGS := BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS
VENDOR_BOOT_FOOTER_ARGS := BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS
diff --git a/core/binary.mk b/core/binary.mk
index 4c68ba7..8c107bd 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -289,25 +289,20 @@
endif
ifneq ($(LOCAL_USE_VNDK),)
- # Required VNDK version for vendor modules is BOARD_VNDK_VERSION.
- my_api_level := $(BOARD_VNDK_VERSION)
- ifeq ($(my_api_level),current)
- # Build with current PLATFORM_VNDK_VERSION.
- # If PLATFORM_VNDK_VERSION has a CODENAME, it will return
- # __ANDROID_API_FUTURE__.
- my_api_level := $(call codename-or-sdk-to-sdk,$(PLATFORM_VNDK_VERSION))
- else
- # Build with current BOARD_VNDK_VERSION.
- my_api_level := $(call codename-or-sdk-to-sdk,$(BOARD_VNDK_VERSION))
- endif
my_cflags += -D__ANDROID_VNDK__
ifneq ($(LOCAL_USE_VNDK_VENDOR),)
- # Vendor modules have LOCAL_USE_VNDK_VENDOR when
- # BOARD_VNDK_VERSION is defined.
+ # Vendor modules have LOCAL_USE_VNDK_VENDOR
my_cflags += -D__ANDROID_VENDOR__
+
+ ifeq ($(BOARD_API_LEVEL),)
+ # TODO(b/314036847): This is a fallback for UDC targets.
+ # This must be a build failure when UDC is no longer built from this source tree.
+ my_cflags += -D__ANDROID_VENDOR_API__=$(PLATFORM_SDK_VERSION)
+ else
+ my_cflags += -D__ANDROID_VENDOR_API__=$(BOARD_API_LEVEL)
+ endif
else ifneq ($(LOCAL_USE_VNDK_PRODUCT),)
- # Product modules have LOCAL_USE_VNDK_PRODUCT when
- # PRODUCT_PRODUCT_VNDK_VERSION is defined.
+ # Product modules have LOCAL_USE_VNDK_PRODUCT
my_cflags += -D__ANDROID_PRODUCT__
endif
endif
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index 83be006..3507961 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -355,6 +355,12 @@
my_sanitize := $(filter-out cfi,$(my_sanitize))
my_cflags += -fno-lto
my_ldflags += -fno-lto
+
+ # TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
+ # discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
+ # doesn't match the linker script due to the "__emutls_v." prefix).
+ my_cflags += -fno-sanitize-coverage=stack-depth
+ my_ldflags += -fno-sanitize-coverage=stack-depth
endif
ifneq ($(filter integer_overflow,$(my_sanitize)),)
diff --git a/core/product.mk b/core/product.mk
index 969b506..91b811d 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -447,6 +447,7 @@
_product_list_vars += PRODUCT_AFDO_PROFILES
_product_single_value_vars += PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API
+_product_single_value_vars += PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE
_product_list_vars += PRODUCT_RELEASE_CONFIG_MAPS
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 30acbba..5fdf416 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -147,6 +147,7 @@
$(call add_json_bool, ArtUseReadBarrier, $(call invert_bool,$(filter false,$(PRODUCT_ART_USE_READ_BARRIER))))
$(call add_json_str, BtConfigIncludeDir, $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR))
$(call add_json_list, DeviceKernelHeaders, $(TARGET_DEVICE_KERNEL_HEADERS) $(TARGET_BOARD_KERNEL_HEADERS) $(TARGET_PRODUCT_KERNEL_HEADERS))
+$(call add_json_str, VendorApiLevel, $(BOARD_API_LEVEL))
$(call add_json_str, DeviceVndkVersion, $(BOARD_VNDK_VERSION))
$(call add_json_str, Platform_vndk_version, $(PLATFORM_VNDK_VERSION))
$(call add_json_list, ExtraVndkVersions, $(PRODUCT_EXTRA_VNDK_VERSIONS))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index f31749b..4226ef6 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -94,6 +94,7 @@
framework-graphics \
framework-minus-apex \
framework-minus-apex-install-dependencies \
+ framework-nfc \
framework-res \
framework-sysconfig.xml \
fsck.erofs \
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index b02a583..55fcf2f 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -50,6 +50,7 @@
PRODUCT_BOOT_JARS += \
framework-minus-apex \
framework-graphics \
+ framework-nfc \
ext \
telephony-common \
voip-common \
diff --git a/target/product/fullmte.mk b/target/product/fullmte.mk
index 5726c06..5e2a694 100644
--- a/target/product/fullmte.mk
+++ b/target/product/fullmte.mk
@@ -25,3 +25,4 @@
SANITIZE_TARGET_DIAG := $(strip $(SANITIZE_TARGET_DIAG) memtag_heap)
endif
PRODUCT_PRODUCT_PROPERTIES += persist.arm64.memtag.default=sync
+PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE := 131072
diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk
index 6c93dd7..219b90c 100644
--- a/target/product/handheld_system.mk
+++ b/target/product/handheld_system.mk
@@ -56,7 +56,6 @@
MmsService \
MtpService \
MusicFX \
- NfcNci \
PacProcessor \
preinstalled-packages-platform-handheld-system.xml \
PrintRecommendationService \
@@ -73,6 +72,7 @@
UserDictionaryProvider \
VpnDialogs \
vr \
+ $(RELEASE_PACKAGE_NFC_STACK)
PRODUCT_SYSTEM_SERVER_APPS += \
diff --git a/tools/OWNERS b/tools/OWNERS
deleted file mode 100644
index 7d666f1..0000000
--- a/tools/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file warn.py,checkowners.py = chh@google.com
diff --git a/tools/aconfig/protos/aconfig.proto b/tools/aconfig/protos/aconfig.proto
index 9e193ec..1a80b04 100644
--- a/tools/aconfig/protos/aconfig.proto
+++ b/tools/aconfig/protos/aconfig.proto
@@ -46,6 +46,7 @@
message flag_declarations {
optional string package = 1;
repeated flag_declaration flag = 2;
+ optional string container = 3;
};
message flag_value {
@@ -79,7 +80,7 @@
repeated tracepoint trace = 8;
optional bool is_fixed_read_only = 9;
optional bool is_exported = 10;
-
+ optional string container = 11;
}
message parsed_flags {
diff --git a/tools/aconfig/src/codegen.rs b/tools/aconfig/src/codegen.rs
index b7fb08f..fef7a3f 100644
--- a/tools/aconfig/src/codegen.rs
+++ b/tools/aconfig/src/codegen.rs
@@ -38,6 +38,10 @@
s.split('.').all(is_valid_name_ident)
}
+pub fn is_valid_container_ident(s: &str) -> bool {
+ is_valid_name_ident(s) || s.split('.').all(is_valid_name_ident)
+}
+
pub fn create_device_config_ident(package: &str, flag_name: &str) -> Result<String> {
ensure!(is_valid_package_ident(package), "bad package");
ensure!(is_valid_name_ident(flag_name), "bad flag name");
@@ -85,6 +89,29 @@
}
#[test]
+ fn test_is_valid_container_ident() {
+ assert!(is_valid_container_ident("foo.bar"));
+ assert!(is_valid_container_ident("foo.bar_baz"));
+ assert!(is_valid_container_ident("foo.bar.a123"));
+ assert!(is_valid_container_ident("foo"));
+ assert!(is_valid_container_ident("foo_bar_123"));
+
+ assert!(!is_valid_container_ident(""));
+ assert!(!is_valid_container_ident("foo._bar"));
+ assert!(!is_valid_container_ident("_foo"));
+ assert!(!is_valid_container_ident("123_foo"));
+ assert!(!is_valid_container_ident("foo-bar"));
+ assert!(!is_valid_container_ident("foo-b\u{00e5}r"));
+ assert!(!is_valid_container_ident("foo.bar.123"));
+ assert!(!is_valid_container_ident(".foo.bar"));
+ assert!(!is_valid_container_ident("foo.bar."));
+ assert!(!is_valid_container_ident("."));
+ assert!(!is_valid_container_ident(".."));
+ assert!(!is_valid_container_ident("foo..bar"));
+ assert!(!is_valid_container_ident("foo.__bar"));
+ }
+
+ #[test]
fn test_create_device_config_ident() {
assert_eq!(
"com.foo.bar.some_flag",
diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs
index 5aa373a..c536260 100644
--- a/tools/aconfig/src/codegen_cpp.rs
+++ b/tools/aconfig/src/codegen_cpp.rs
@@ -162,6 +162,8 @@
virtual bool disabled_rw() = 0;
+ virtual bool disabled_rw_exported() = 0;
+
virtual bool disabled_rw_in_other_namespace() = 0;
virtual bool enabled_fixed_ro() = 0;
@@ -181,6 +183,10 @@
return provider_->disabled_rw();
}
+inline bool disabled_rw_exported() {
+ return provider_->disabled_rw_exported();
+}
+
inline bool disabled_rw_in_other_namespace() {
return provider_->disabled_rw_in_other_namespace();
}
@@ -206,6 +212,8 @@
bool com_android_aconfig_test_disabled_rw();
+bool com_android_aconfig_test_disabled_rw_exported();
+
bool com_android_aconfig_test_disabled_rw_in_other_namespace();
bool com_android_aconfig_test_enabled_fixed_ro();
@@ -241,6 +249,10 @@
virtual void disabled_rw(bool val) = 0;
+ virtual bool disabled_rw_exported() = 0;
+
+ virtual void disabled_rw_exported(bool val) = 0;
+
virtual bool disabled_rw_in_other_namespace() = 0;
virtual void disabled_rw_in_other_namespace(bool val) = 0;
@@ -278,6 +290,14 @@
provider_->disabled_rw(val);
}
+inline bool disabled_rw_exported() {
+ return provider_->disabled_rw_exported();
+}
+
+inline void disabled_rw_exported(bool val) {
+ provider_->disabled_rw_exported(val);
+}
+
inline bool disabled_rw_in_other_namespace() {
return provider_->disabled_rw_in_other_namespace();
}
@@ -327,6 +347,10 @@
void set_com_android_aconfig_test_disabled_rw(bool val);
+bool com_android_aconfig_test_disabled_rw_exported();
+
+void set_com_android_aconfig_test_disabled_rw_exported(bool val);
+
bool com_android_aconfig_test_disabled_rw_in_other_namespace();
void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val);
@@ -377,14 +401,24 @@
return cache_[0];
}
- virtual bool disabled_rw_in_other_namespace() override {
+ virtual bool disabled_rw_exported() override {
if (cache_[1] == -1) {
cache_[1] = server_configurable_flags::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.disabled_rw_exported",
+ "false") == "true";
+ }
+ return cache_[1];
+ }
+
+ virtual bool disabled_rw_in_other_namespace() override {
+ if (cache_[2] == -1) {
+ cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
"com.android.aconfig.test.disabled_rw_in_other_namespace",
"false") == "true";
}
- return cache_[1];
+ return cache_[2];
}
virtual bool enabled_fixed_ro() override {
@@ -396,17 +430,17 @@
}
virtual bool enabled_rw() override {
- if (cache_[2] == -1) {
- cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
+ if (cache_[3] == -1) {
+ cache_[3] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.aconfig_test",
"com.android.aconfig.test.enabled_rw",
"true") == "true";
}
- return cache_[2];
+ return cache_[3];
}
private:
- std::vector<int8_t> cache_ = std::vector<int8_t>(3, -1);
+ std::vector<int8_t> cache_ = std::vector<int8_t>(4, -1);
};
std::unique_ptr<flag_provider_interface> provider_ =
@@ -421,6 +455,10 @@
return com::android::aconfig::test::disabled_rw();
}
+bool com_android_aconfig_test_disabled_rw_exported() {
+ return com::android::aconfig::test::disabled_rw_exported();
+}
+
bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
return com::android::aconfig::test::disabled_rw_in_other_namespace();
}
@@ -485,6 +523,22 @@
overrides_["disabled_rw"] = val;
}
+ virtual bool disabled_rw_exported() override {
+ auto it = overrides_.find("disabled_rw_exported");
+ if (it != overrides_.end()) {
+ return it->second;
+ } else {
+ return server_configurable_flags::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.disabled_rw_exported",
+ "false") == "true";
+ }
+ }
+
+ virtual void disabled_rw_exported(bool val) override {
+ overrides_["disabled_rw_exported"] = val;
+ }
+
virtual bool disabled_rw_in_other_namespace() override {
auto it = overrides_.find("disabled_rw_in_other_namespace");
if (it != overrides_.end()) {
@@ -570,11 +624,20 @@
com::android::aconfig::test::disabled_rw(val);
}
+
+bool com_android_aconfig_test_disabled_rw_exported() {
+ return com::android::aconfig::test::disabled_rw_exported();
+}
+
+void set_com_android_aconfig_test_disabled_rw_exported(bool val) {
+ com::android::aconfig::test::disabled_rw_exported(val);
+}
+
+
bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
return com::android::aconfig::test::disabled_rw_in_other_namespace();
}
-
void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val) {
com::android::aconfig::test::disabled_rw_in_other_namespace(val);
}
@@ -634,6 +697,8 @@
match mode {
CodegenMode::Production => EXPORTED_PROD_HEADER_EXPECTED,
CodegenMode::Test => EXPORTED_TEST_HEADER_EXPECTED,
+ CodegenMode::Exported =>
+ todo!("exported mode not yet supported for cpp, see b/313894653."),
},
generated_files_map.get(&target_file_path).unwrap()
)
@@ -647,6 +712,8 @@
match mode {
CodegenMode::Production => PROD_SOURCE_FILE_EXPECTED,
CodegenMode::Test => TEST_SOURCE_FILE_EXPECTED,
+ CodegenMode::Exported =>
+ todo!("exported mode not yet supported for cpp, see b/313894653."),
},
generated_files_map.get(&target_file_path).unwrap()
)
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index a822cd5..b3e5e6c 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -39,6 +39,7 @@
flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect();
let is_read_write = flag_elements.iter().any(|elem| elem.is_read_write);
let is_test_mode = codegen_mode == CodegenMode::Test;
+ let library_exported = codegen_mode == CodegenMode::Exported;
let context = Context {
flag_elements,
namespace_flags,
@@ -46,6 +47,7 @@
is_read_write,
properties_set,
package_name: package.to_string(),
+ library_exported,
};
let mut template = TinyTemplate::new();
template.add_template("Flags.java", include_str!("../templates/Flags.java.template"))?;
@@ -103,6 +105,7 @@
pub is_read_write: bool,
pub properties_set: BTreeSet<String>,
pub package_name: String,
+ pub library_exported: bool,
}
#[derive(Serialize, Debug)]
@@ -120,6 +123,7 @@
pub is_read_write: bool,
pub method_name: String,
pub properties: String,
+ pub exported: bool,
}
fn create_flag_element(package: &str, pf: &ProtoParsedFlag) -> FlagElement {
@@ -133,6 +137,7 @@
is_read_write: pf.permission() == ProtoFlagPermission::READ_WRITE,
method_name: format_java_method_name(pf.name()),
properties: format_property_name(pf.namespace()),
+ exported: pf.is_exported.unwrap_or(false),
}
}
@@ -179,6 +184,8 @@
@UnsupportedAppUsage
boolean disabledRw();
@UnsupportedAppUsage
+ boolean disabledRwExported();
+ @UnsupportedAppUsage
boolean disabledRwInOtherNamespace();
@com.android.aconfig.annotations.AssumeTrueForR8
@UnsupportedAppUsage
@@ -202,6 +209,8 @@
/** @hide */
public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
/** @hide */
+ public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported";
+ /** @hide */
public static final String FLAG_DISABLED_RW_IN_OTHER_NAMESPACE = "com.android.aconfig.test.disabled_rw_in_other_namespace";
/** @hide */
public static final String FLAG_ENABLED_FIXED_RO = "com.android.aconfig.test.enabled_fixed_ro";
@@ -220,6 +229,10 @@
return FEATURE_FLAGS.disabledRw();
}
@UnsupportedAppUsage
+ public static boolean disabledRwExported() {
+ return FEATURE_FLAGS.disabledRwExported();
+ }
+ @UnsupportedAppUsage
public static boolean disabledRwInOtherNamespace() {
return FEATURE_FLAGS.disabledRwInOtherNamespace();
}
@@ -262,6 +275,11 @@
}
@Override
@UnsupportedAppUsage
+ public boolean disabledRwExported() {
+ return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
+ }
+ @Override
+ @UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
}
@@ -302,6 +320,7 @@
Map.ofEntries(
Map.entry(Flags.FLAG_DISABLED_RO, false),
Map.entry(Flags.FLAG_DISABLED_RW, false),
+ Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
Map.entry(Flags.FLAG_ENABLED_RO, false),
@@ -336,6 +355,7 @@
private static boolean aconfig_test_is_cached = false;
private static boolean other_namespace_is_cached = false;
private static boolean disabledRw = false;
+ private static boolean disabledRwExported = false;
private static boolean disabledRwInOtherNamespace = false;
private static boolean enabledRw = true;
@@ -345,6 +365,8 @@
Properties properties = DeviceConfig.getProperties("aconfig_test");
disabledRw =
properties.getBoolean("com.android.aconfig.test.disabled_rw", false);
+ disabledRwExported =
+ properties.getBoolean("com.android.aconfig.test.disabled_rw_exported", false);
enabledRw =
properties.getBoolean("com.android.aconfig.test.enabled_rw", true);
} catch (NullPointerException e) {
@@ -394,6 +416,14 @@
}
@Override
@UnsupportedAppUsage
+ public boolean disabledRwExported() {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
+ return disabledRwExported;
+ }
+ @Override
+ @UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
if (!other_namespace_is_cached) {
load_overrides_other_namespace();
@@ -449,6 +479,202 @@
}
#[test]
+ fn test_generate_java_code_exported() {
+ let parsed_flags = crate::test::parse_test_flags();
+ let generated_files = generate_java_code(
+ crate::test::TEST_PACKAGE,
+ parsed_flags.parsed_flag.iter(),
+ CodegenMode::Exported,
+ )
+ .unwrap();
+
+ let expect_flags_content = r#"
+ package com.android.aconfig.test;
+ // TODO(b/303773055): Remove the annotation after access issue is resolved.
+ import android.compat.annotation.UnsupportedAppUsage;
+ /** @hide */
+ public final class Flags {
+ /** @hide */
+ public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
+ /** @hide */
+ public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported";
+
+ @UnsupportedAppUsage
+ public static boolean disabledRw() {
+ return FEATURE_FLAGS.disabledRw();
+ }
+ @UnsupportedAppUsage
+ public static boolean disabledRwExported() {
+ return FEATURE_FLAGS.disabledRwExported();
+ }
+ private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+ }
+ "#;
+
+ let expect_feature_flags_content = r#"
+ package com.android.aconfig.test;
+ // TODO(b/303773055): Remove the annotation after access issue is resolved.
+ import android.compat.annotation.UnsupportedAppUsage;
+ /** @hide */
+ public interface FeatureFlags {
+ @UnsupportedAppUsage
+ boolean disabledRw();
+ @UnsupportedAppUsage
+ boolean disabledRwExported();
+ }
+ "#;
+
+ let expect_feature_flags_impl_content = r#"
+ package com.android.aconfig.test;
+ // TODO(b/303773055): Remove the annotation after access issue is resolved.
+ import android.compat.annotation.UnsupportedAppUsage;
+ import android.provider.DeviceConfig;
+ import android.provider.DeviceConfig.Properties;
+ /** @hide */
+ public final class FeatureFlagsImpl implements FeatureFlags {
+ private static boolean aconfig_test_is_cached = false;
+ private static boolean other_namespace_is_cached = false;
+ private static boolean disabledRw = false;
+ private static boolean disabledRwExported = false;
+
+
+ private void load_overrides_aconfig_test() {
+ try {
+ Properties properties = DeviceConfig.getProperties("aconfig_test");
+ disabledRw =
+ properties.getBoolean("com.android.aconfig.test.disabled_rw", false);
+ disabledRwExported =
+ properties.getBoolean("com.android.aconfig.test.disabled_rw_exported", false);
+ } 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
+ );
+ }
+ aconfig_test_is_cached = true;
+ }
+
+ private void load_overrides_other_namespace() {
+ try {
+ Properties properties = DeviceConfig.getProperties("other_namespace");
+ } 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
+ );
+ }
+ other_namespace_is_cached = true;
+ }
+
+ @Override
+ @UnsupportedAppUsage
+ public boolean disabledRw() {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
+ return disabledRw;
+ }
+
+ @Override
+ @UnsupportedAppUsage
+ public boolean disabledRwExported() {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
+ return disabledRwExported;
+ }
+ }"#;
+
+ let expect_fake_feature_flags_impl_content = r#"
+ package com.android.aconfig.test;
+ // TODO(b/303773055): Remove the annotation after access issue is resolved.
+ import android.compat.annotation.UnsupportedAppUsage;
+ import java.util.HashMap;
+ import java.util.Map;
+ /** @hide */
+ public class FakeFeatureFlagsImpl implements FeatureFlags {
+ public FakeFeatureFlagsImpl() {
+ resetAll();
+ }
+ @Override
+ @UnsupportedAppUsage
+ public boolean disabledRw() {
+ return getValue(Flags.FLAG_DISABLED_RW);
+ }
+ @Override
+ @UnsupportedAppUsage
+ public boolean disabledRwExported() {
+ return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
+ }
+ public void setFlag(String flagName, boolean value) {
+ if (!this.mFlagMap.containsKey(flagName)) {
+ throw new IllegalArgumentException("no such flag " + flagName);
+ }
+ this.mFlagMap.put(flagName, value);
+ }
+ public void resetAll() {
+ for (Map.Entry entry : mFlagMap.entrySet()) {
+ entry.setValue(null);
+ }
+ }
+ private boolean getValue(String flagName) {
+ Boolean value = this.mFlagMap.get(flagName);
+ if (value == null) {
+ throw new IllegalArgumentException(flagName + " is not set");
+ }
+ return value;
+ }
+ private Map<String, Boolean> mFlagMap = new HashMap<>(
+ Map.ofEntries(
+ Map.entry(Flags.FLAG_DISABLED_RO, false),
+ Map.entry(Flags.FLAG_DISABLED_RW, false),
+ Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
+ Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
+ Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
+ Map.entry(Flags.FLAG_ENABLED_RO, false),
+ Map.entry(Flags.FLAG_ENABLED_RW, false)
+ )
+ );
+ }
+ "#;
+
+ let mut file_set = HashMap::from([
+ ("com/android/aconfig/test/Flags.java", expect_flags_content),
+ ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content),
+ ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
+ (
+ "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
+ expect_fake_feature_flags_impl_content,
+ ),
+ ]);
+
+ for file in generated_files {
+ let file_path = file.path.to_str().unwrap();
+ assert!(file_set.contains_key(file_path), "Cannot find {}", file_path);
+ assert_eq!(
+ None,
+ crate::test::first_significant_code_diff(
+ file_set.get(file_path).unwrap(),
+ &String::from_utf8(file.contents).unwrap()
+ ),
+ "File {} content is not correct",
+ file_path
+ );
+ file_set.remove(file_path);
+ }
+
+ assert!(file_set.is_empty());
+ }
+
+ #[test]
fn test_generate_java_code_test() {
let parsed_flags = crate::test::parse_test_flags();
let generated_files = generate_java_code(
@@ -489,6 +715,12 @@
}
@Override
@UnsupportedAppUsage
+ public boolean disabledRwExported() {
+ throw new UnsupportedOperationException(
+ "Method is not implemented.");
+ }
+ @Override
+ @UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
throw new UnsupportedOperationException(
"Method is not implemented.");
diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs
index d8675e7..502cec8 100644
--- a/tools/aconfig/src/codegen_rust.rs
+++ b/tools/aconfig/src/codegen_rust.rs
@@ -45,6 +45,9 @@
match codegen_mode {
CodegenMode::Production => include_str!("../templates/rust_prod.template"),
CodegenMode::Test => include_str!("../templates/rust_test.template"),
+ CodegenMode::Exported => {
+ todo!("exported mode not yet supported for rust, see b/313894653.")
+ }
},
)?;
let contents = template.render("rust_code_gen", &context)?;
@@ -104,6 +107,12 @@
"com.android.aconfig.test.disabled_rw",
"false") == "true";
+ /// flag value cache for disabled_rw_exported
+ static ref CACHED_disabled_rw_exported: bool = 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 ref CACHED_disabled_rw_in_other_namespace: bool = flags_rust::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
@@ -115,6 +124,7 @@
"aconfig_flags.aconfig_test",
"com.android.aconfig.test.enabled_rw",
"true") == "true";
+
}
impl FlagProvider {
@@ -128,6 +138,11 @@
*CACHED_disabled_rw
}
+ /// query flag disabled_rw_exported
+ pub fn disabled_rw_exported(&self) -> bool {
+ *CACHED_disabled_rw_exported
+ }
+
/// query flag disabled_rw_in_other_namespace
pub fn disabled_rw_in_other_namespace(&self) -> bool {
*CACHED_disabled_rw_in_other_namespace
@@ -164,6 +179,12 @@
PROVIDER.disabled_rw()
}
+/// query flag disabled_rw_exported
+#[inline(always)]
+pub fn disabled_rw_exported() -> bool {
+ PROVIDER.disabled_rw_exported()
+}
+
/// query flag disabled_rw_in_other_namespace
#[inline(always)]
pub fn disabled_rw_in_other_namespace() -> bool {
@@ -228,6 +249,21 @@
self.overrides.insert("disabled_rw", val);
}
+ /// query flag disabled_rw_exported
+ pub fn disabled_rw_exported(&self) -> bool {
+ self.overrides.get("disabled_rw_exported").copied().unwrap_or(
+ flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.disabled_rw_exported",
+ "false") == "true"
+ )
+ }
+
+ /// set flag disabled_rw_exported
+ pub fn set_disabled_rw_exported(&mut self, val: bool) {
+ self.overrides.insert("disabled_rw_exported", val);
+ }
+
/// query flag disabled_rw_in_other_namespace
pub fn disabled_rw_in_other_namespace(&self) -> bool {
self.overrides.get("disabled_rw_in_other_namespace").copied().unwrap_or(
@@ -317,6 +353,18 @@
PROVIDER.lock().unwrap().set_disabled_rw(val);
}
+/// query flag disabled_rw_exported
+#[inline(always)]
+pub fn disabled_rw_exported() -> bool {
+ PROVIDER.lock().unwrap().disabled_rw_exported()
+}
+
+/// set flag disabled_rw_exported
+#[inline(always)]
+pub fn set_disabled_rw_exported(val: bool) {
+ PROVIDER.lock().unwrap().set_disabled_rw_exported(val);
+}
+
/// query flag disabled_rw_in_other_namespace
#[inline(always)]
pub fn disabled_rw_in_other_namespace() -> bool {
@@ -383,6 +431,8 @@
match mode {
CodegenMode::Production => PROD_EXPECTED,
CodegenMode::Test => TEST_EXPECTED,
+ CodegenMode::Exported =>
+ todo!("exported mode not yet supported for rust, see b/313894653."),
},
&String::from_utf8(generated.contents).unwrap()
)
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index ed7489f..37ee79e 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -57,6 +57,7 @@
pub fn parse_flags(
package: &str,
+ container: Option<&str>,
declarations: Vec<Input>,
values: Vec<Input>,
default_permission: ProtoFlagPermission,
@@ -79,12 +80,24 @@
package,
flag_declarations.package()
);
+ if let Some(c) = container {
+ ensure!(
+ c == flag_declarations.container(),
+ "failed to parse {}: expected container {}, got {}",
+ input.source,
+ c,
+ flag_declarations.container()
+ );
+ }
for mut flag_declaration in flag_declarations.flag.into_iter() {
crate::protos::flag_declaration::verify_fields(&flag_declaration)
.with_context(|| input.error_context())?;
// create ParsedFlag using FlagDeclaration and default values
let mut parsed_flag = ProtoParsedFlag::new();
+ if let Some(c) = container {
+ parsed_flag.set_container(c.to_string());
+ }
parsed_flag.set_package(package.to_string());
parsed_flag.set_name(flag_declaration.take_name());
parsed_flag.set_namespace(flag_declaration.take_namespace());
@@ -171,6 +184,7 @@
pub enum CodegenMode {
Production,
Test,
+ Exported,
}
pub fn create_java_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
@@ -261,9 +275,10 @@
DumpFormat::Text => {
for parsed_flag in parsed_flags.parsed_flag.into_iter() {
let line = format!(
- "{}.{}: {:?} + {:?}\n",
+ "{}.{} [{}]: {:?} + {:?}\n",
parsed_flag.package(),
parsed_flag.name(),
+ parsed_flag.container(),
parsed_flag.permission(),
parsed_flag.state()
);
@@ -275,9 +290,10 @@
let sources: Vec<_> =
parsed_flag.trace.iter().map(|tracepoint| tracepoint.source()).collect();
let line = format!(
- "{}.{}: {:?} + {:?} ({})\n",
+ "{}.{} [{}]: {:?} + {:?} ({})\n",
parsed_flag.package(),
parsed_flag.name(),
+ parsed_flag.container(),
parsed_flag.permission(),
parsed_flag.state(),
sources.join(", ")
@@ -335,7 +351,7 @@
assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state());
assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission());
- assert_eq!(6, parsed_flags.parsed_flag.len());
+ assert_eq!(7, parsed_flags.parsed_flag.len());
for pf in parsed_flags.parsed_flag.iter() {
if pf.name() == "enabled_fixed_ro" {
continue;
@@ -376,6 +392,7 @@
let flags_bytes = crate::commands::parse_flags(
"com.first",
+ None,
declaration,
value,
ProtoFlagPermission::READ_ONLY,
@@ -390,9 +407,72 @@
}
#[test]
+ fn test_parse_flags_package_mismatch_between_declaration_and_command_line() {
+ let first_flag = r#"
+ package: "com.declaration.package"
+ container: "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 value: Vec<Input> = vec![];
+
+ let error = crate::commands::parse_flags(
+ "com.argument.package",
+ Some("first.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_WRITE,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "failed to parse memory: expected package com.argument.package, got com.declaration.package"
+ );
+ }
+
+ #[test]
+ fn test_parse_flags_container_mismatch_between_declaration_and_command_line() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "declaration.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 value: Vec<Input> = vec![];
+
+ let error = crate::commands::parse_flags(
+ "com.first",
+ Some("argument.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_WRITE,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "failed to parse memory: expected container argument.container, got declaration.container"
+ );
+ }
+
+ #[test]
fn test_parse_flags_override_fixed_read_only() {
let first_flag = r#"
package: "com.first"
+ container: "com.first.container"
flag {
name: "first"
namespace: "first_ns"
@@ -418,6 +498,7 @@
}];
let error = crate::commands::parse_flags(
"com.first",
+ Some("com.first.container"),
declaration,
value,
ProtoFlagPermission::READ_WRITE,
@@ -434,7 +515,7 @@
let input = parse_test_flags_as_input();
let bytes = create_device_config_defaults(input).unwrap();
let text = std::str::from_utf8(&bytes).unwrap();
- assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\nother_namespace:com.android.aconfig.test.disabled_rw_in_other_namespace=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
+ assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.disabled_rw_exported=disabled\nother_namespace:com.android.aconfig.test.disabled_rw_in_other_namespace=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
}
#[test]
@@ -442,7 +523,7 @@
let input = parse_test_flags_as_input();
let bytes = create_device_config_sysprops(input).unwrap();
let text = std::str::from_utf8(&bytes).unwrap();
- assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.disabled_rw_in_other_namespace=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
+ assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.disabled_rw_exported=false\npersist.device_config.com.android.aconfig.test.disabled_rw_in_other_namespace=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
}
#[test]
@@ -450,7 +531,9 @@
let input = parse_test_flags_as_input();
let bytes = dump_parsed_flags(vec![input], DumpFormat::Text, false).unwrap();
let text = std::str::from_utf8(&bytes).unwrap();
- assert!(text.contains("com.android.aconfig.test.disabled_ro: READ_ONLY + DISABLED"));
+ assert!(
+ text.contains("com.android.aconfig.test.disabled_ro [system]: READ_ONLY + DISABLED")
+ );
}
#[test]
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index 17c388d..90464c5 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -42,6 +42,8 @@
.subcommand(
Command::new("create-cache")
.arg(Arg::new("package").long("package").required(true))
+ // TODO(b/312769710): Make this argument required.
+ .arg(Arg::new("container").long("container"))
.arg(Arg::new("declarations").long("declarations").action(ArgAction::Append))
.arg(Arg::new("values").long("values").action(ArgAction::Append))
.arg(
@@ -120,6 +122,13 @@
.ok_or(anyhow!("internal error: required argument '{}' not found", arg_name))
}
+fn get_optional_arg<'a, T>(matches: &'a ArgMatches, arg_name: &str) -> Option<&'a T>
+where
+ T: Any + Clone + Send + Sync + 'static,
+{
+ matches.get_one::<T>(arg_name)
+}
+
fn open_zero_or_more_files(matches: &ArgMatches, arg_name: &str) -> Result<Vec<Input>> {
let mut opened_files = vec![];
for path in matches.get_many::<String>(arg_name).unwrap_or_default() {
@@ -168,12 +177,20 @@
match matches.subcommand() {
Some(("create-cache", sub_matches)) => {
let package = get_required_arg::<String>(sub_matches, "package")?;
+ let container =
+ get_optional_arg::<String>(sub_matches, "container").map(|c| c.as_str());
let declarations = open_zero_or_more_files(sub_matches, "declarations")?;
let values = open_zero_or_more_files(sub_matches, "values")?;
let default_permission =
get_required_arg::<protos::ProtoFlagPermission>(sub_matches, "default-permission")?;
- let output = commands::parse_flags(package, declarations, values, *default_permission)
- .context("failed to create cache")?;
+ let output = commands::parse_flags(
+ package,
+ container,
+ declarations,
+ values,
+ *default_permission,
+ )
+ .context("failed to create cache")?;
let path = get_required_arg::<String>(sub_matches, "cache")?;
write_output_to_file_or_stdout(path, &output)?;
}
diff --git a/tools/aconfig/src/protos.rs b/tools/aconfig/src/protos.rs
index 8e76468..3d9089c 100644
--- a/tools/aconfig/src/protos.rs
+++ b/tools/aconfig/src/protos.rs
@@ -111,11 +111,16 @@
pub fn verify_fields(pdf: &ProtoFlagDeclarations) -> Result<()> {
ensure_required_fields!("flag declarations", pdf, "package");
+ // TODO(b/312769710): Make the container field required.
ensure!(
codegen::is_valid_package_ident(pdf.package()),
"bad flag declarations: bad package"
);
+ ensure!(
+ !pdf.has_container() || codegen::is_valid_container_ident(pdf.container()),
+ "bad flag declarations: bad container"
+ );
for flag_declaration in pdf.flag.iter() {
super::flag_declaration::verify_fields(flag_declaration)?;
}
@@ -207,6 +212,10 @@
);
ensure!(codegen::is_valid_package_ident(pf.package()), "bad parsed flag: bad package");
+ ensure!(
+ !pf.has_container() || codegen::is_valid_container_ident(pf.container()),
+ "bad parsed flag: bad container"
+ );
ensure!(codegen::is_valid_name_ident(pf.name()), "bad parsed flag: bad name");
ensure!(codegen::is_valid_name_ident(pf.namespace()), "bad parsed flag: bad namespace");
ensure!(!pf.description().is_empty(), "bad parsed flag: empty description");
@@ -309,6 +318,7 @@
let flag_declarations = flag_declarations::try_from_text_proto(
r#"
package: "com.foo.bar"
+container: "system"
flag {
name: "first"
namespace: "first_ns"
@@ -327,6 +337,7 @@
)
.unwrap();
assert_eq!(flag_declarations.package(), "com.foo.bar");
+ assert_eq!(flag_declarations.container(), "system");
let first = flag_declarations.flag.iter().find(|pf| pf.name() == "first").unwrap();
assert_eq!(first.name(), "first");
assert_eq!(first.namespace(), "first_ns");
@@ -342,9 +353,26 @@
assert!(second.is_fixed_read_only());
assert!(!second.is_exported());
+ // valid input: missing container in flag declarations is supported
+ let flag_declarations = flag_declarations::try_from_text_proto(
+ r#"
+package: "com.foo.bar"
+flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+}
+"#,
+ )
+ .unwrap();
+ assert_eq!(flag_declarations.container(), "");
+ assert!(!flag_declarations.has_container());
+
// bad input: missing package in flag declarations
let error = flag_declarations::try_from_text_proto(
r#"
+container: "system"
flag {
name: "first"
namespace: "first_ns"
@@ -364,6 +392,7 @@
let error = flag_declarations::try_from_text_proto(
r#"
package: "com.foo.bar"
+container: "system"
flag {
name: "first"
description: "This is the description of the first flag."
@@ -382,6 +411,7 @@
let error = flag_declarations::try_from_text_proto(
r#"
package: "_com.FOO__BAR"
+container: "system"
flag {
name: "first"
namespace: "first_ns"
@@ -401,6 +431,7 @@
let error = flag_declarations::try_from_text_proto(
r#"
package: "com.foo.bar"
+container: "system"
flag {
name: "FIRST"
namespace: "first_ns"
@@ -420,6 +451,7 @@
let error = flag_declarations::try_from_text_proto(
r#"
package: "com.foo.bar"
+container: "system"
flag {
name: "first"
namespace: "first_ns"
@@ -434,6 +466,7 @@
let error = flag_declarations::try_from_text_proto(
r#"
package: "com.foo.bar"
+container: "system"
flag {
name: "first"
namespace: "first_ns"
@@ -445,6 +478,25 @@
)
.unwrap_err();
assert!(format!("{:?}", error).contains("bad flag declaration: exactly one bug required"));
+
+ // bad input: invalid container name in flag declaration
+ let error = flag_declarations::try_from_text_proto(
+ r#"
+package: "com.foo.bar"
+container: "__bad_bad_container.com"
+flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ bug: "abc"
+}
+"#,
+ )
+ .unwrap_err();
+ assert!(format!("{:?}", error).contains("bad flag declarations: bad container"));
+
+ // TODO(b/312769710): Verify error when container is missing.
}
#[test]
@@ -559,6 +611,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
parsed_flag {
package: "com.second"
@@ -579,6 +632,7 @@
permission: READ_ONLY
}
is_fixed_read_only: true
+ container: "system"
}
"#;
let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
@@ -613,6 +667,7 @@
description: "This is the description of the first flag."
state: DISABLED
permission: READ_ONLY
+ container: "system"
}
"#;
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
@@ -631,6 +686,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
@@ -651,6 +707,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
parsed_flag {
package: "aaa.aaa"
@@ -665,6 +722,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
@@ -688,6 +746,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
parsed_flag {
package: "com.foo"
@@ -702,6 +761,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
@@ -725,6 +785,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
parsed_flag {
package: "com.foo"
@@ -739,6 +800,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
@@ -766,6 +828,7 @@
state: ENABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
@@ -792,6 +855,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
parsed_flag {
package: "com.second"
@@ -806,6 +870,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let expected = try_from_binary_proto_from_text_proto(text_proto).unwrap();
@@ -824,6 +889,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let first = try_from_binary_proto_from_text_proto(text_proto).unwrap();
@@ -842,6 +908,7 @@
state: DISABLED
permission: READ_ONLY
}
+ container: "system"
}
"#;
let second = try_from_binary_proto_from_text_proto(text_proto).unwrap();
diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs
index 31c67b3..8df4493 100644
--- a/tools/aconfig/src/test.rs
+++ b/tools/aconfig/src/test.rs
@@ -43,6 +43,7 @@
}
is_fixed_read_only: false
is_exported: false
+ container: "system"
}
parsed_flag {
package: "com.android.aconfig.test"
@@ -59,6 +60,29 @@
}
is_fixed_read_only: false
is_exported: true
+ container: "system"
+}
+parsed_flag {
+ package: "com.android.aconfig.test"
+ name: "disabled_rw_exported"
+ namespace: "aconfig_test"
+ description: "This flag is exported"
+ bug: "111"
+ state: DISABLED
+ permission: READ_WRITE
+ trace {
+ source: "tests/test.aconfig"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ trace {
+ source: "tests/first.values"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ is_fixed_read_only: false
+ is_exported: true
+ container: "system"
}
parsed_flag {
package: "com.android.aconfig.test"
@@ -80,6 +104,7 @@
}
is_fixed_read_only: false
is_exported: false
+ container: "system"
}
parsed_flag {
package: "com.android.aconfig.test"
@@ -101,6 +126,7 @@
}
is_fixed_read_only: true
is_exported: false
+ container: "system"
}
parsed_flag {
package: "com.android.aconfig.test"
@@ -127,6 +153,7 @@
}
is_fixed_read_only: false
is_exported: false
+ container: "system"
}
parsed_flag {
package: "com.android.aconfig.test"
@@ -148,12 +175,14 @@
}
is_fixed_read_only: false
is_exported: false
+ container: "system"
}
"#;
pub fn parse_test_flags() -> ProtoParsedFlags {
let bytes = crate::commands::parse_flags(
"com.android.aconfig.test",
+ Some("system"),
vec![Input {
source: "tests/test.aconfig".to_string(),
reader: Box::new(include_bytes!("../tests/test.aconfig").as_slice()),
diff --git a/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template b/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template
index 933d6a7..fd2e26a 100644
--- a/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template
@@ -12,11 +12,23 @@
}
{{ for item in flag_elements}}
+{{ if library_exported }}
+
+{{ if item.exported }}
@Override
@UnsupportedAppUsage
public boolean {item.method_name}() \{
return getValue(Flags.FLAG_{item.flag_name_constant_suffix});
}
+{{ endif }}
+
+{{ else }}
+ @Override
+ @UnsupportedAppUsage
+ public boolean {item.method_name}() \{
+ return getValue(Flags.FLAG_{item.flag_name_constant_suffix});
+ }
+{{ endif }}
{{ endfor}}
public void setFlag(String flagName, boolean value) \{
if (!this.mFlagMap.containsKey(flagName)) \{
diff --git a/tools/aconfig/templates/FeatureFlags.java.template b/tools/aconfig/templates/FeatureFlags.java.template
index da850ae..180f882 100644
--- a/tools/aconfig/templates/FeatureFlags.java.template
+++ b/tools/aconfig/templates/FeatureFlags.java.template
@@ -5,6 +5,15 @@
/** @hide */
public interface FeatureFlags \{
{{ for item in flag_elements }}
+{{ if library_exported }}
+
+{{ if item.exported }}
+ @UnsupportedAppUsage
+ boolean {item.method_name}();
+{{ endif }}
+
+{{ else }}
+
{{ -if not item.is_read_write }}
{{ -if item.default_value }}
@com.android.aconfig.annotations.AssumeTrueForR8
@@ -14,5 +23,7 @@
{{ endif }}
@UnsupportedAppUsage
boolean {item.method_name}();
+
+{{ endif }}
{{ endfor }}
}
diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
index ec8822c..a15c859 100644
--- a/tools/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -14,9 +14,17 @@
{{- endfor- }}
{{ for flag in flag_elements }}
+{{ if library_exported }}
+{{ if flag.exported }}
+ private static boolean {flag.method_name} = false;
+{{ endif }}
+
+{{ else }}
+
{{- if flag.is_read_write }}
private static boolean {flag.method_name} = {flag.default_value};
{{- endif- }}
+{{ endif }}
{{ endfor }}
{{ for namespace_with_flags in namespace_flags }}
@@ -25,10 +33,21 @@
Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
{{- for flag in namespace_with_flags.flags }}
- {{- if flag.is_read_write }}
+ {{ if library_exported }}
+
+ {{ if flag.exported }}
+ {flag.method_name} =
+ properties.getBoolean("{flag.device_config_flag}", false);
+ {{ endif }}
+
+ {{ else }}
+
+ {{ if flag.is_read_write }}
{flag.method_name} =
properties.getBoolean("{flag.device_config_flag}", {flag.default_value});
- {{- endif- }}
+ {{ endif }}
+
+ {{ endif }}
{{ endfor }}
} catch (NullPointerException e) \{
throw new RuntimeException(
@@ -46,6 +65,9 @@
{{ endif- }}
{{ for flag in flag_elements }}
+{{ if library_exported }}
+
+{{ if flag.exported }}
@Override
@UnsupportedAppUsage
public boolean {flag.method_name}() \{
@@ -58,6 +80,23 @@
return {flag.default_value};
{{ endif- }}
}
+{{ endif }}
+
+{{ else }}
+ @Override
+ @UnsupportedAppUsage
+ public boolean {flag.method_name}() \{
+ {{ -if flag.is_read_write }}
+ if (!{flag.device_config_namespace}_is_cached) \{
+ load_overrides_{flag.device_config_namespace}();
+ }
+ return {flag.method_name};
+ {{ else }}
+ return {flag.default_value};
+ {{ endif- }}
+ }
+{{ endif }}
+
{{ endfor }}
}
{{ else }}
diff --git a/tools/aconfig/templates/Flags.java.template b/tools/aconfig/templates/Flags.java.template
index cf6604c..9f4c52f 100644
--- a/tools/aconfig/templates/Flags.java.template
+++ b/tools/aconfig/templates/Flags.java.template
@@ -6,10 +6,28 @@
/** @hide */
public final class Flags \{
{{- for item in flag_elements}}
+ {{ if library_exported }}
+ {{ if item.exported }}
/** @hide */
public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}";
+ {{ endif }}
+ {{ else }}
+ /** @hide */
+ public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}";
+ {{ endif }}
{{- endfor }}
{{ for item in flag_elements}}
+{{ if library_exported }}
+
+{{ if item.exported }}
+ @UnsupportedAppUsage
+ public static boolean {item.method_name}() \{
+ return FEATURE_FLAGS.{item.method_name}();
+ }
+{{ endif }}
+
+{{ else }}
+
{{ -if not item.is_read_write }}
{{ -if item.default_value }}
@com.android.aconfig.annotations.AssumeTrueForR8
@@ -21,6 +39,7 @@
public static boolean {item.method_name}() \{
return FEATURE_FLAGS.{item.method_name}();
}
+{{ endif }}
{{ endfor }}
{{ -if is_test_mode }}
public static void setFeatureFlags(FeatureFlags featureFlags) \{
diff --git a/tools/aconfig/tests/first.values b/tools/aconfig/tests/first.values
index 07d8d1d..b248d43 100644
--- a/tools/aconfig/tests/first.values
+++ b/tools/aconfig/tests/first.values
@@ -28,3 +28,9 @@
state: ENABLED
permission: READ_ONLY
}
+flag_value {
+ package: "com.android.aconfig.test"
+ name: "disabled_rw_exported"
+ state: DISABLED
+ permission: READ_WRITE
+}
diff --git a/tools/aconfig/tests/test.aconfig b/tools/aconfig/tests/test.aconfig
index b49b665..e44d154 100644
--- a/tools/aconfig/tests/test.aconfig
+++ b/tools/aconfig/tests/test.aconfig
@@ -1,4 +1,5 @@
package: "com.android.aconfig.test"
+container: "system"
# This flag's final value is calculated from:
# - test.aconfig: DISABLED + READ_WRITE (default)
@@ -59,3 +60,11 @@
description: "This flag is DISABLED + READ_WRITE, and is defined in another namespace"
bug: "999"
}
+
+flag {
+ name: "disabled_rw_exported"
+ namespace: "aconfig_test"
+ description: "This flag is exported"
+ bug: "111"
+ is_exported: true
+}
\ No newline at end of file
diff --git a/tools/checkowners.py b/tools/checkowners.py
deleted file mode 100755
index f037321..0000000
--- a/tools/checkowners.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/python
-
-"""Parse and check syntax errors of a given OWNERS file."""
-
-import argparse
-import re
-import sys
-import urllib.request, urllib.parse, urllib.error
-import urllib.request, urllib.error, urllib.parse
-
-parser = argparse.ArgumentParser(description='Check OWNERS file syntax')
-parser.add_argument('-v', '--verbose', dest='verbose',
- action='store_true', default=False,
- help='Verbose output to debug')
-parser.add_argument('-c', '--check_address', dest='check_address',
- action='store_true', default=False,
- help='Check email addresses')
-parser.add_argument(dest='owners', metavar='OWNERS', nargs='+',
- help='Path to OWNERS file')
-args = parser.parse_args()
-
-gerrit_server = 'https://android-review.googlesource.com'
-checked_addresses = {}
-
-
-def echo(msg):
- if args.verbose:
- print(msg)
-
-
-def find_address(address):
- if address not in checked_addresses:
- request = (gerrit_server + '/accounts/?n=1&q=email:'
- + urllib.parse.quote(address))
- echo('Checking email address: ' + address)
- result = urllib.request.urlopen(request).read()
- checked_addresses[address] = result.find('"_account_id":') >= 0
- if checked_addresses[address]:
- echo('Found email address: ' + address)
- return checked_addresses[address]
-
-
-def check_address(fname, num, address):
- if find_address(address):
- return 0
- print('%s:%d: ERROR: unknown email address: %s' % (fname, num, address))
- return 1
-
-
-def main():
- # One regular expression to check all valid lines.
- noparent = 'set +noparent'
- email = '([^@ ]+@[^ @]+|\\*)'
- emails = '(%s( *, *%s)*)' % (email, email)
- file_directive = 'file: *([^ :]+ *: *)?[^ ]+'
- directive = '(%s|%s|%s)' % (emails, noparent, file_directive)
- glob = '[a-zA-Z0-9_\\.\\-\\*\\?]+'
- globs = '(%s( *, *%s)*)' % (glob, glob)
- perfile = 'per-file +' + globs + ' *= *' + directive
- include = 'include +([^ :]+ *: *)?[^ ]+'
- pats = '(|%s|%s|%s|%s|%s)$' % (noparent, email, perfile, include, file_directive)
- patterns = re.compile(pats)
- address_pattern = re.compile('([^@ ]+@[^ @]+)')
- perfile_pattern = re.compile('per-file +.*=(.*)')
-
- error = 0
- for fname in args.owners:
- echo('Checking file: ' + fname)
- num = 0
- for line in open(fname, 'r'):
- num += 1
- stripped_line = re.sub('#.*$', '', line).strip()
- if not patterns.match(stripped_line):
- error += 1
- print('%s:%d: ERROR: unknown line [%s]' % (fname, num, line.strip()))
- elif args.check_address:
- if perfile_pattern.match(stripped_line):
- for addr in perfile_pattern.match(stripped_line).group(1).split(','):
- a = addr.strip()
- if a and a != '*':
- error += check_address(fname, num, addr.strip())
- elif address_pattern.match(stripped_line):
- error += check_address(fname, num, stripped_line)
- sys.exit(error)
-
-if __name__ == '__main__':
- main()
diff --git a/tools/finalization/README.md b/tools/finalization/README.md
index 501f260..cc97d1f 100644
--- a/tools/finalization/README.md
+++ b/tools/finalization/README.md
@@ -12,10 +12,8 @@
## CI:
Performed in build targets in Finalization branches.
-1. [Finalization Step 1 for Main, git_main-fina-1-release](https://android-build.googleplex.com/builds/branches/git_main-fina-1-release/grid). Test [1st step/Finalize SDK](./finalize-aidl-vndk-sdk-resources.sh).
-2. [Finalization Step 1 for UDC, git_udc-fina-1-release](https://android-build.googleplex.com/builds/branches/git_udc-fina-1-release/grid). Same but for udc-dev.
-3. [Finalization Step 2 for Main, git_main-fina-2-release](https://android-build.googleplex.com/builds/branches/git_main-fina-2-release/grid). Test [1st step/Finalize SDK](./finalize-aidl-vndk-sdk-resources.sh) and [2nd step/Finalize Android](./finalize-sdk-rel.sh). Use [local finalization](./localonly-steps.sh) to build and copy presubmits.
-4. [Finalization Step 2 for UDC, git_udc-fina-2-release](https://android-build.googleplex.com/builds/branches/git_udc-fina-2-release/grid). Same but for udc-dev.
+1. [Finalization Step 1, git_main-fina-1-release](https://android-build.corp.google.com/build_explorer/branch/git_main-fina-1-release). Test [1st step/Finalize SDK](./finalize-aidl-vndk-sdk-resources.sh).
+3. [Finalization Step 2, git_main-fina-2-release](https://android-build.corp.google.com/build_explorer/branch/git_main-fina-2-release). Test [1st step/Finalize SDK](./finalize-aidl-vndk-sdk-resources.sh) and [2nd step/Finalize Android](./finalize-sdk-rel.sh). Use [local finalization](./localonly-steps.sh) to build and copy presubmits.
5. [Local finalization steps](./localonly-steps.sh) are done only during local testing or in the CI lab. Normally these steps use artifacts from other builds.
## Utility:
diff --git a/tools/finalization/finalize-aidl-vndk-sdk-resources.sh b/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
index 6d13325..37c0011 100755
--- a/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
+++ b/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
@@ -137,6 +137,13 @@
local version_codes="$top/platform_testing/libraries/compatibility-common-util/src/com/android/compatibility/common/util/VersionCodes.java"
sed -i -e "/=.*$((${FINAL_PLATFORM_SDK_VERSION}-1));/a \\ ${SDK_VERSION}" $version_codes
+ # tools/platform-compat
+ local class2nonsdklist="$top/tools/platform-compat/java/com/android/class2nonsdklist/Class2NonSdkList.java"
+ if ! grep -q "\.*map.put($((${FINAL_PLATFORM_SDK_VERSION}))" $class2nonsdklist ; then
+ local sdk_version="map.put(${FINAL_PLATFORM_SDK_VERSION}, FLAG_UNSUPPORTED);"
+ sed -i -e "/.*map.put($((${FINAL_PLATFORM_SDK_VERSION}-1))/a \\ ${sdk_version}" $class2nonsdklist
+ fi
+
# Finalize resources
"$top/frameworks/base/tools/aapt2/tools/finalize_res.py" \
"$top/frameworks/base/core/res/res/values/public-staging.xml" \
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 5f99f6c..ee266b7 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -168,6 +168,7 @@
"apexd_host",
"brillo_update_payload",
"checkvintf",
+ "generate_gki_certificate",
"lz4",
"toybox",
"unpack_bootimg",
@@ -244,6 +245,7 @@
"boot_signer",
"brotli",
"bsdiff",
+ "generate_gki_certificate",
"imgdiff",
"lz4",
"mkbootfs",
@@ -308,6 +310,7 @@
"brotli",
"bsdiff",
"deapexer",
+ "generate_gki_certificate",
"imgdiff",
"lz4",
"mkbootfs",
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 34b7172..bde152f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -437,6 +437,8 @@
sldc_flags = sldc_flags_str.split()
build_command.append(str(len(sldc_flags)))
build_command.extend(sldc_flags)
+ f2fs_blocksize = prop_dict.get("f2fs_blocksize", "4096")
+ build_command.extend(["-b", f2fs_blocksize])
else:
raise BuildImageError(
"Error: unknown filesystem type: {}".format(fs_type))
@@ -721,6 +723,7 @@
"system_f2fs_compress",
"system_f2fs_sldc_flags",
"f2fs_sparse_flag",
+ "f2fs_blocksize",
"skip_fsck",
"ext_mkuserimg",
"avb_enable",
@@ -770,6 +773,7 @@
(True, "{}_extfs_inode_count", "extfs_inode_count"),
(True, "{}_f2fs_compress", "f2fs_compress"),
(True, "{}_f2fs_sldc_flags", "f2fs_sldc_flags"),
+ (True, "{}_f2fs_blocksize", "f2fs_block_size"),
(True, "{}_reserved_size", "partition_reserved_size"),
(True, "{}_squashfs_block_size", "squashfs_block_size"),
(True, "{}_squashfs_compressor", "squashfs_compressor"),
@@ -817,7 +821,6 @@
d["mount_point"] = mount_point
if mount_point == "system":
copy_prop("system_headroom", "partition_headroom")
- copy_prop("system_root_image", "system_root_image")
copy_prop("root_dir", "root_dir")
copy_prop("root_fs_config", "root_fs_config")
elif mount_point == "data":
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index a4c92ae..63fd854 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1156,8 +1156,7 @@
return self.build_props.get(prop)
-def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
- system_root_image=False):
+def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path):
class Partition(object):
def __init__(self, mount_point, fs_type, device, length, context, slotselect):
self.mount_point = mount_point
@@ -1216,12 +1215,6 @@
device=pieces[0], length=length, context=context,
slotselect=slotselect)
- # / is used for the system mount point when the root directory is included in
- # system. Other areas assume system is always at "/system" so point /system
- # at /.
- if system_root_image:
- assert '/system' not in d and '/' in d
- d["/system"] = d["/"]
return d
@@ -1237,22 +1230,19 @@
# ../RAMDISK/system/etc/recovery.fstab. This function has to handle both
# cases, since it may load the info_dict from an old build (e.g. when
# generating incremental OTAs from that build).
- system_root_image = info_dict.get('system_root_image') == 'true'
if info_dict.get('no_recovery') != 'true':
recovery_fstab_path = 'RECOVERY/RAMDISK/system/etc/recovery.fstab'
if not DoesInputFileContain(input_file, recovery_fstab_path):
recovery_fstab_path = 'RECOVERY/RAMDISK/etc/recovery.fstab'
return LoadRecoveryFSTab(
- read_helper, info_dict['fstab_version'], recovery_fstab_path,
- system_root_image)
+ read_helper, info_dict['fstab_version'], recovery_fstab_path)
if info_dict.get('recovery_as_boot') == 'true':
recovery_fstab_path = 'BOOT/RAMDISK/system/etc/recovery.fstab'
if not DoesInputFileContain(input_file, recovery_fstab_path):
recovery_fstab_path = 'BOOT/RAMDISK/etc/recovery.fstab'
return LoadRecoveryFSTab(
- read_helper, info_dict['fstab_version'], recovery_fstab_path,
- system_root_image)
+ read_helper, info_dict['fstab_version'], recovery_fstab_path)
return None
@@ -1575,6 +1565,50 @@
pubkey_path=pubkey_path)
+def _HasGkiCertificationArgs():
+ return ("gki_signing_key_path" in OPTIONS.info_dict and
+ "gki_signing_algorithm" in OPTIONS.info_dict)
+
+
+def _GenerateGkiCertificate(image, image_name):
+ key_path = OPTIONS.info_dict.get("gki_signing_key_path")
+ algorithm = OPTIONS.info_dict.get("gki_signing_algorithm")
+
+ key_path = ResolveAVBSigningPathArgs(key_path)
+
+ # Checks key_path exists, before processing --gki_signing_* args.
+ if not os.path.exists(key_path):
+ raise ExternalError(
+ 'gki_signing_key_path: "{}" not found'.format(key_path))
+
+ output_certificate = tempfile.NamedTemporaryFile()
+ cmd = [
+ "generate_gki_certificate",
+ "--name", image_name,
+ "--algorithm", algorithm,
+ "--key", key_path,
+ "--output", output_certificate.name,
+ image,
+ ]
+
+ signature_args = OPTIONS.info_dict.get("gki_signing_signature_args", "")
+ signature_args = signature_args.strip()
+ if signature_args:
+ cmd.extend(["--additional_avb_args", signature_args])
+
+ args = OPTIONS.info_dict.get("avb_boot_add_hash_footer_args", "")
+ args = args.strip()
+ if args:
+ cmd.extend(["--additional_avb_args", args])
+
+ RunAndCheckOutput(cmd)
+
+ output_certificate.seek(os.SEEK_SET, 0)
+ data = output_certificate.read()
+ output_certificate.close()
+ return data
+
+
def BuildVBMeta(image_path, partitions, name, needed_partitions,
resolve_rollback_index_location_conflict=False):
"""Creates a VBMeta image.
@@ -1797,6 +1831,29 @@
RunAndCheckOutput(cmd)
+ if _HasGkiCertificationArgs():
+ if not os.path.exists(img.name):
+ raise ValueError("Cannot find GKI boot.img")
+ if kernel_path is None or not os.path.exists(kernel_path):
+ raise ValueError("Cannot find GKI kernel.img")
+
+ # Certify GKI images.
+ boot_signature_bytes = b''
+ boot_signature_bytes += _GenerateGkiCertificate(img.name, "boot")
+ boot_signature_bytes += _GenerateGkiCertificate(
+ kernel_path, "generic_kernel")
+
+ BOOT_SIGNATURE_SIZE = 16 * 1024
+ if len(boot_signature_bytes) > BOOT_SIGNATURE_SIZE:
+ raise ValueError(
+ f"GKI boot_signature size must be <= {BOOT_SIGNATURE_SIZE}")
+ boot_signature_bytes += (
+ b'\0' * (BOOT_SIGNATURE_SIZE - len(boot_signature_bytes)))
+ assert len(boot_signature_bytes) == BOOT_SIGNATURE_SIZE
+
+ with open(img.name, 'ab') as f:
+ f.write(boot_signature_bytes)
+
# Sign the image if vboot is non-empty.
if info_dict.get("vboot"):
path = "/" + partition_name
@@ -1910,10 +1967,8 @@
if info_dict.get("recovery_as_boot") == "true":
return True # the recovery-as-boot boot.img has a RECOVERY ramdisk.
- if info_dict.get("system_root_image") == "true":
- # The ramdisk content is merged into the system.img, so there is NO
- # ramdisk in the boot.img or boot-<kernel version>.img.
- return False
+ if info_dict.get("gki_boot_image_without_ramdisk") == "true":
+ return False # A GKI boot.img has no ramdisk since Android-13.
if info_dict.get("init_boot") == "true":
# The ramdisk is moved to the init_boot.img, so there is NO
@@ -3783,14 +3838,11 @@
output_sink(recovery_img_path, recovery_img.data)
else:
- system_root_image = info_dict.get("system_root_image") == "true"
include_recovery_dtbo = info_dict.get("include_recovery_dtbo") == "true"
include_recovery_acpio = info_dict.get("include_recovery_acpio") == "true"
path = os.path.join(input_dir, recovery_resource_dat_path)
- # With system-root-image, boot and recovery images will have mismatching
- # entries (only recovery has the ramdisk entry) (Bug: 72731506). Use bsdiff
- # to handle such a case.
- if system_root_image or include_recovery_dtbo or include_recovery_acpio:
+ # Use bsdiff to handle mismatching entries (Bug: 72731506)
+ if include_recovery_dtbo or include_recovery_acpio:
diff_program = ["bsdiff"]
bonus_args = ""
assert not os.path.exists(path)
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 2fbb3b0..5867c6f 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -83,9 +83,8 @@
--replace_verity_public_key <key>
Replace the certificate (public key) used for verity verification. The
- key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
- for devices using system_root_image). It expects the key filename WITH
- the extension (e.g. verity_key.pub).
+ key file replaces the one at BOOT/RAMDISK/verity_key. It expects the key
+ filename WITH the extension (e.g. verity_key.pub).
--replace_verity_keyid <path_to_X509_PEM_cert_file>
Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
@@ -123,6 +122,17 @@
mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
args will be appended to the existing ones in info dict.
+ --gki_signing_algorithm <algorithm>
+ --gki_signing_key <key>
+ Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
+ 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
+ in info dict.
+
+ --gki_signing_extra_args <args>
+ Specify any additional args that are needed to generate 'boot signature'
+ (e.g. --prop foo:bar). The args will be appended to the existing ones
+ in info dict.
+
--android_jar_path <path>
Path to the android.jar to repack the apex file.
@@ -182,6 +192,9 @@
OPTIONS.avb_keys = {}
OPTIONS.avb_algorithms = {}
OPTIONS.avb_extra_args = {}
+OPTIONS.gki_signing_key = None
+OPTIONS.gki_signing_algorithm = None
+OPTIONS.gki_signing_extra_args = None
OPTIONS.android_jar_path = None
OPTIONS.vendor_partitions = set()
OPTIONS.vendor_otatools = None
@@ -538,11 +551,9 @@
[len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
except ValueError:
- # Sets this to zero for targets without APK files.
+ # Sets this to zero for targets without APK files, e.g., gki_arm64.
maxsize = 0
- system_root_image = misc_info.get("system_root_image") == "true"
-
for info in input_tf_zip.infolist():
filename = info.filename
if filename.startswith("IMAGES/"):
@@ -754,6 +765,9 @@
if misc_info.get('avb_enable') == 'true':
RewriteAvbProps(misc_info)
+ # Replace the GKI signing key for boot.img, if any.
+ ReplaceGkiSigningKey(misc_info)
+
# Write back misc_info with the latest values.
ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
@@ -1035,6 +1049,27 @@
misc_info[args_key] = result
+def ReplaceGkiSigningKey(misc_info):
+ """Replaces the GKI signing key."""
+
+ key = OPTIONS.gki_signing_key
+ if not key:
+ return
+
+ algorithm = OPTIONS.gki_signing_algorithm
+ if not algorithm:
+ raise ValueError("Missing --gki_signing_algorithm")
+
+ print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
+ misc_info["gki_signing_algorithm"] = algorithm
+ misc_info["gki_signing_key_path"] = key
+
+ extra_args = OPTIONS.gki_signing_extra_args
+ if extra_args:
+ print('Setting GKI signing args: "%s"' % (extra_args))
+ misc_info["gki_signing_signature_args"] = extra_args
+
+
def BuildKeyMap(misc_info, key_mapping_options):
for s, d in key_mapping_options:
if s is None: # -d option
@@ -1388,6 +1423,12 @@
# 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
partition, extra_args = a.split("=", 1)
OPTIONS.avb_extra_args[partition] = extra_args
+ elif o == "--gki_signing_key":
+ OPTIONS.gki_signing_key = a
+ elif o == "--gki_signing_algorithm":
+ OPTIONS.gki_signing_algorithm = a
+ elif o == "--gki_signing_extra_args":
+ OPTIONS.gki_signing_extra_args = a
elif o == "--vendor_otatools":
OPTIONS.vendor_otatools = a
elif o == "--vendor_partitions":
@@ -1451,6 +1492,9 @@
"avb_extra_custom_image_key=",
"avb_extra_custom_image_algorithm=",
"avb_extra_custom_image_extra_args=",
+ "gki_signing_key=",
+ "gki_signing_algorithm=",
+ "gki_signing_extra_args=",
"vendor_partitions=",
"vendor_otatools=",
"allow_gsi_debug_sepolicy",
diff --git a/tools/releasetools/test_build_image.py b/tools/releasetools/test_build_image.py
index cfae7a5..d4f7ccc 100644
--- a/tools/releasetools/test_build_image.py
+++ b/tools/releasetools/test_build_image.py
@@ -99,11 +99,10 @@
}
self.assertRaises(BuildImageError, CheckHeadroom, ext4fs_output, prop_dict)
- def test_SetUpInDirAndFsConfig_SystemRootImageTrue_NonSystem(self):
+ def test_SetUpInDirAndFsConfig_NonSystem(self):
prop_dict = {
'fs_config': 'fs-config',
'mount_point': 'vendor',
- 'system_root_image': 'true',
}
in_dir, fs_config = SetUpInDirAndFsConfig('/path/to/in_dir', prop_dict)
self.assertEqual('/path/to/in_dir', in_dir)
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index c61c290..9b2e667 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -1348,7 +1348,6 @@
INFO_DICT_DEFAULT = {
'recovery_api_version': 3,
'fstab_version': 2,
- 'system_root_image': 'true',
'no_recovery': 'true',
'recovery_as_boot': 'true',
}
@@ -1377,14 +1376,8 @@
info_values = ''.join(
['{}={}\n'.format(k, v) for k, v in sorted(info_dict.items())])
common.ZipWriteStr(target_files_zip, 'META/misc_info.txt', info_values)
-
- FSTAB_TEMPLATE = "/dev/block/system {} ext4 ro,barrier=1 defaults"
- if info_dict.get('system_root_image') == 'true':
- fstab_values = FSTAB_TEMPLATE.format('/')
- else:
- fstab_values = FSTAB_TEMPLATE.format('/system')
- common.ZipWriteStr(target_files_zip, fstab_path, fstab_values)
-
+ common.ZipWriteStr(target_files_zip, fstab_path,
+ "/dev/block/system /system ext4 ro,barrier=1 defaults")
common.ZipWriteStr(
target_files_zip, 'META/file_contexts', 'file-contexts')
return target_files
@@ -1397,7 +1390,6 @@
loaded_dict = common.LoadInfoDict(target_files_zip)
self.assertEqual(3, loaded_dict['recovery_api_version'])
self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
def test_LoadInfoDict_legacyRecoveryFstabPath(self):
@@ -1408,7 +1400,6 @@
loaded_dict = common.LoadInfoDict(target_files_zip)
self.assertEqual(3, loaded_dict['recovery_api_version'])
self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
@test_utils.SkipIfExternalToolsUnavailable()
@@ -1420,7 +1411,6 @@
loaded_dict = common.LoadInfoDict(unzipped)
self.assertEqual(3, loaded_dict['recovery_api_version'])
self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
@test_utils.SkipIfExternalToolsUnavailable()
@@ -1432,15 +1422,11 @@
loaded_dict = common.LoadInfoDict(unzipped)
self.assertEqual(3, loaded_dict['recovery_api_version'])
self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
- def test_LoadInfoDict_systemRootImageFalse(self):
- # Devices not using system-as-root nor recovery-as-boot. Non-A/B devices
- # launched prior to P will likely have this config.
+ def test_LoadInfoDict_recoveryAsBootFalse(self):
info_dict = copy.copy(self.INFO_DICT_DEFAULT)
del info_dict['no_recovery']
- del info_dict['system_root_image']
del info_dict['recovery_as_boot']
target_files = self._test_LoadInfoDict_createTargetFiles(
info_dict,
@@ -1452,22 +1438,6 @@
self.assertNotIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
- def test_LoadInfoDict_recoveryAsBootFalse(self):
- # Devices using system-as-root, but with standalone recovery image. Non-A/B
- # devices launched since P will likely have this config.
- info_dict = copy.copy(self.INFO_DICT_DEFAULT)
- del info_dict['no_recovery']
- del info_dict['recovery_as_boot']
- target_files = self._test_LoadInfoDict_createTargetFiles(
- info_dict,
- 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
- with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
- loaded_dict = common.LoadInfoDict(target_files_zip)
- self.assertEqual(3, loaded_dict['recovery_api_version'])
- self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
- self.assertIn('/system', loaded_dict['fstab'])
-
def test_LoadInfoDict_noRecoveryTrue(self):
# Device doesn't have a recovery partition at all.
info_dict = copy.copy(self.INFO_DICT_DEFAULT)
@@ -1499,7 +1469,6 @@
loaded_dict = common.LoadInfoDict(unzipped, True)
self.assertEqual(3, loaded_dict['recovery_api_version'])
self.assertEqual(2, loaded_dict['fstab_version'])
- self.assertIn('/', loaded_dict['fstab'])
self.assertIn('/system', loaded_dict['fstab'])
self.assertEqual(
os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir'])
@@ -1636,6 +1605,40 @@
self.assertEqual(3, chained_partition_args.rollback_index_location)
self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
+ def test_GenerateGkiCertificate_KeyPathNotFound(self):
+ pubkey = os.path.join(self.testdata_dir, 'no_testkey_gki.pem')
+ self.assertFalse(os.path.exists(pubkey))
+
+ common.OPTIONS.info_dict = {
+ 'gki_signing_key_path': pubkey,
+ 'gki_signing_algorithm': 'SHA256_RSA4096',
+ 'gki_signing_signature_args': '--prop foo:bar',
+ }
+ common.OPTIONS.search_path = None
+ test_file = tempfile.NamedTemporaryFile()
+ self.assertRaises(common.ExternalError, common._GenerateGkiCertificate,
+ test_file.name, 'generic_kernel')
+
+ def test_GenerateGkiCertificate_SearchKeyPathNotFound(self):
+ pubkey = 'no_testkey_gki.pem'
+ self.assertFalse(os.path.exists(pubkey))
+
+ # Tests it should raise ExternalError if no key found under
+ # OPTIONS.search_path.
+ search_path_dir = common.MakeTempDir()
+ search_pubkey = os.path.join(search_path_dir, pubkey)
+ self.assertFalse(os.path.exists(search_pubkey))
+
+ common.OPTIONS.search_path = search_path_dir
+ common.OPTIONS.info_dict = {
+ 'gki_signing_key_path': pubkey,
+ 'gki_signing_algorithm': 'SHA256_RSA4096',
+ 'gki_signing_signature_args': '--prop foo:bar',
+ }
+ test_file = tempfile.NamedTemporaryFile()
+ self.assertRaises(common.ExternalError, common._GenerateGkiCertificate,
+ test_file.name, 'generic_kernel')
+
class InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
"""Checks the format of install-recovery.sh.
diff --git a/tools/releasetools/test_sign_target_files_apks.py b/tools/releasetools/test_sign_target_files_apks.py
index 9cc6df4..0cd7dac 100644
--- a/tools/releasetools/test_sign_target_files_apks.py
+++ b/tools/releasetools/test_sign_target_files_apks.py
@@ -23,7 +23,8 @@
import test_utils
from sign_target_files_apks import (
CheckApkAndApexKeysAvailable, EditTags, GetApkFileInfo, ReadApexKeysInfo,
- ReplaceCerts, RewriteAvbProps, RewriteProps, WriteOtacerts)
+ ReplaceCerts, ReplaceGkiSigningKey, RewriteAvbProps, RewriteProps,
+ WriteOtacerts)
class SignTargetFilesApksTest(test_utils.ReleaseToolsTestCase):
@@ -535,3 +536,52 @@
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey', None),
}, keys_info)
+
+ def test_ReplaceGkiSigningKey(self):
+ common.OPTIONS.gki_signing_key = 'release_gki_key'
+ common.OPTIONS.gki_signing_algorithm = 'release_gki_algorithm'
+ common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args'
+
+ misc_info = {
+ 'gki_signing_key_path': 'default_gki_key',
+ 'gki_signing_algorithm': 'default_gki_algorithm',
+ 'gki_signing_signature_args': 'default_gki_signature_args',
+ }
+ expected_dict = {
+ 'gki_signing_key_path': 'release_gki_key',
+ 'gki_signing_algorithm': 'release_gki_algorithm',
+ 'gki_signing_signature_args': 'release_gki_signature_extra_args',
+ }
+ ReplaceGkiSigningKey(misc_info)
+ self.assertDictEqual(expected_dict, misc_info)
+
+ def test_ReplaceGkiSigningKey_MissingSigningAlgorithm(self):
+ common.OPTIONS.gki_signing_key = 'release_gki_key'
+ common.OPTIONS.gki_signing_algorithm = None
+ common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args'
+
+ misc_info = {
+ 'gki_signing_key_path': 'default_gki_key',
+ 'gki_signing_algorithm': 'default_gki_algorithm',
+ 'gki_signing_signature_args': 'default_gki_signature_args',
+ }
+ self.assertRaises(ValueError, ReplaceGkiSigningKey, misc_info)
+
+ def test_ReplaceGkiSigningKey_MissingSigningKeyNop(self):
+ common.OPTIONS.gki_signing_key = None
+ common.OPTIONS.gki_signing_algorithm = 'release_gki_algorithm'
+ common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args'
+
+ # No change to misc_info if common.OPTIONS.gki_signing_key is missing.
+ misc_info = {
+ 'gki_signing_key_path': 'default_gki_key',
+ 'gki_signing_algorithm': 'default_gki_algorithm',
+ 'gki_signing_signature_args': 'default_gki_signature_args',
+ }
+ expected_dict = {
+ 'gki_signing_key_path': 'default_gki_key',
+ 'gki_signing_algorithm': 'default_gki_algorithm',
+ 'gki_signing_signature_args': 'default_gki_signature_args',
+ }
+ ReplaceGkiSigningKey(misc_info)
+ self.assertDictEqual(expected_dict, misc_info)
diff --git a/tools/releasetools/test_validate_target_files.py b/tools/releasetools/test_validate_target_files.py
index 48b563d..4d4b9e5 100644
--- a/tools/releasetools/test_validate_target_files.py
+++ b/tools/releasetools/test_validate_target_files.py
@@ -156,7 +156,6 @@
verity_key_mincrypt)
info_dict = {
- 'system_root_image' : 'true',
'verity' : 'true',
}
options = {
diff --git a/tools/releasetools/validate_target_files.py b/tools/releasetools/validate_target_files.py
index 84a2f7e..8da4fa2 100755
--- a/tools/releasetools/validate_target_files.py
+++ b/tools/releasetools/validate_target_files.py
@@ -132,7 +132,7 @@
return
# Verify IMAGES/system.img if applicable.
- # Some targets are system.img-less.
+ # Some targets, e.g., gki_arm64, gki_x86_64, etc., are system.img-less.
if 'IMAGES/system.img' in input_zip.namelist():
CheckAllFiles('system')
@@ -361,18 +361,15 @@
"Mismatching mincrypt verity key files"
logging.info('Verified the content of /verity_key')
- # For devices with a separate ramdisk (i.e. non-system-as-root), there must
- # be a copy in ramdisk.
- if info_dict.get("system_root_image") != "true":
- verity_key_ramdisk = os.path.join(
- input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
- assert os.path.exists(
- verity_key_ramdisk), 'Missing verity_key in ramdisk'
+ verity_key_ramdisk = os.path.join(
+ input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
+ assert os.path.exists(
+ verity_key_ramdisk), 'Missing verity_key in ramdisk'
- assert filecmp.cmp(
- verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
- 'Mismatching verity_key files in root and ramdisk'
- logging.info('Verified the content of /verity_key in ramdisk')
+ assert filecmp.cmp(
+ verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
+ 'Mismatching verity_key files in root and ramdisk'
+ logging.info('Verified the content of /verity_key in ramdisk')
# Then verify the verity signed system/vendor/product images, against the
# verity pubkey in mincrypt format.