Merge "Add fingerprint info to package context." into main
diff --git a/ci/build_device_and_tests b/ci/build_device_and_tests
new file mode 100755
index 0000000..9d11268
--- /dev/null
+++ b/ci/build_device_and_tests
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+#
+# Copyright 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.
+
+build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
diff --git a/core/java_common.mk b/core/java_common.mk
index a21f062..f574b76 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -32,7 +32,7 @@
else ifneq (,$(LOCAL_SDK_VERSION)$(TARGET_BUILD_USE_PREBUILT_SDKS))
# TODO(ccross): allow 1.9 for current and unbundled once we have SDK system modules
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
- else ifeq ($(EXPERIMENTAL_TARGET_JAVA_VERSION_21),true)
+ else ifeq ($(RELEASE_TARGET_JAVA_21),true)
LOCAL_JAVA_LANGUAGE_VERSION := 21
else
LOCAL_JAVA_LANGUAGE_VERSION := 17
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 2f69d06..32ca660 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -437,7 +437,7 @@
$(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, BoardInitBootimagePartitionSize, $(BOARD_INIT_BOOT_IMAGE_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))
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index e2bb1ad..bfdf1a7 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -513,11 +513,19 @@
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;
@@ -536,6 +544,55 @@
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
@@ -547,8 +604,14 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRw() {
- if (!isCached) {
- init();
+ if (isReadFromNew) {
+ if (!isCached) {
+ init();
+ }
+ } else {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
}
return disabledRw;
}
@@ -556,8 +619,14 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwExported() {
- if (!isCached) {
- init();
+ if (isReadFromNew) {
+ if (!isCached) {
+ init();
+ }
+ } else {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
}
return disabledRwExported;
}
@@ -565,8 +634,14 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
- if (!isCached) {
- init();
+ if (isReadFromNew) {
+ if (!isCached) {
+ init();
+ }
+ } else {
+ if (!other_namespace_is_cached) {
+ load_overrides_other_namespace();
+ }
}
return disabledRwInOtherNamespace;
}
@@ -598,8 +673,14 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean enabledRw() {
- if (!isCached) {
- init();
+ if (isReadFromNew) {
+ if (!isCached) {
+ init();
+ }
+ } else {
+ if (!aconfig_test_is_cached) {
+ load_overrides_aconfig_test();
+ }
}
return enabledRw;
}
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index ef1b4f6..4bc72f7 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -83,7 +83,7 @@
p.boolean_start_index = boolean_start_index;
boolean_start_index += p.boolean_flags.len() as u32;
- if version > 2 {
+ 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);
@@ -202,6 +202,7 @@
assert!(packages[0].flag_names.contains("disabled_rw"));
assert!(packages[0].flag_names.contains("enabled_ro"));
assert_eq!(packages[0].boolean_start_index, 0);
+ assert_eq!(packages[0].fingerprint, 0);
assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
assert_eq!(packages[1].package_id, 1);
@@ -210,6 +211,7 @@
assert!(packages[1].flag_names.contains("disabled_rw"));
assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
assert_eq!(packages[1].boolean_start_index, 3);
+ assert_eq!(packages[0].fingerprint, 0);
assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
assert_eq!(packages[2].package_id, 2);
@@ -217,5 +219,49 @@
assert!(packages[2].flag_names.contains("enabled_rw"));
assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
assert_eq!(packages[2].boolean_start_index, 6);
+ assert_eq!(packages[2].fingerprint, 0);
+ }
+
+ #[test]
+ fn test_flag_package_with_fingerprint() {
+ let caches = parse_all_test_flags();
+ let packages = group_flags_by_package(caches.iter(), 2);
+
+ for pkg in packages.iter() {
+ let pkg_name = pkg.package_name;
+ assert_eq!(pkg.flag_names.len(), pkg.boolean_flags.len());
+ for pf in pkg.boolean_flags.iter() {
+ assert!(pkg.flag_names.contains(pf.name()));
+ assert_eq!(pf.package(), pkg_name);
+ }
+ }
+
+ assert_eq!(packages.len(), 3);
+
+ assert_eq!(packages[0].package_name, "com.android.aconfig.storage.test_1");
+ assert_eq!(packages[0].package_id, 0);
+ assert_eq!(packages[0].flag_names.len(), 3);
+ assert!(packages[0].flag_names.contains("enabled_rw"));
+ assert!(packages[0].flag_names.contains("disabled_rw"));
+ assert!(packages[0].flag_names.contains("enabled_ro"));
+ assert_eq!(packages[0].boolean_start_index, 0);
+ assert_eq!(packages[0].fingerprint, 15248948510590158086u64);
+
+ assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
+ assert_eq!(packages[1].package_id, 1);
+ assert_eq!(packages[1].flag_names.len(), 3);
+ assert!(packages[1].flag_names.contains("enabled_ro"));
+ assert!(packages[1].flag_names.contains("disabled_rw"));
+ assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
+ assert_eq!(packages[1].boolean_start_index, 3);
+ assert_eq!(packages[1].fingerprint, 4431940502274857964u64);
+
+ assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
+ assert_eq!(packages[2].package_id, 2);
+ assert_eq!(packages[2].flag_names.len(), 2);
+ assert!(packages[2].flag_names.contains("enabled_rw"));
+ assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
+ assert_eq!(packages[2].boolean_start_index, 6);
+ assert_eq!(packages[2].fingerprint, 16233229917711622375u64);
}
}
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index d782f81..cb52150 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,22 +1,41 @@
package {package_name};
{{ -if not is_test_mode }}
{{ -if allow_instrumentation }}
-{{ if not library_exported- }}{#- only new storage for prod mode #}
+{{ if not library_exported- }}
// 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;
@@ -34,37 +53,9 @@
{{ -endfor }}
isCached = true;
}
-{{ -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 }}
+{{ endif }}
+
+
{{ for namespace_with_flags in namespace_flags }}
private void load_overrides_{namespace_with_flags.namespace}() \{
final long ident = Binder.clearCallingIdentity();
@@ -93,17 +84,40 @@
{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/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 4cd5070..1c5b7c5 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -42,3 +42,14 @@
host_supported: true,
is_stubs_module: true,
}
+
+java_library {
+ name: "aconfig_storage_stub_none",
+ srcs: [
+ "src/android/os/flagging/**/*.java",
+ ],
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ host_supported: true,
+ is_stubs_module: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
new file mode 100644
index 0000000..3cac516
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackage {
+ public static AconfigPackage load(String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
new file mode 100644
index 0000000..5f066a8
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackageInternal {
+
+ public static AconfigPackageInternal load(String container, String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static AconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException getException() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..c1bc19b
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class PlatformAconfigPackageInternal {
+
+ public static PlatformAconfigPackageInternal load(String container, String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException getException() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}