Merge "aconfig: update aconfig_storage_file crate" into main
diff --git a/core/Makefile b/core/Makefile
index 9c97d661..93f88c0 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -5061,9 +5061,12 @@
 check_vintf_all_deps :=
 
 # -----------------------------------------------------------------
-# Activate vendor APEXes for checkvintf
+# Activate APEXes for checkvintf
 
 apex_dirs := \
+  $(TARGET_OUT)/apex/% \
+  $(TARGET_OUT_PRODUCT)/apex/% \
+  $(TARGET_OUT_SYSTEM_EXT)/apex/% \
   $(TARGET_OUT_VENDOR)/apex/% \
 
 apex_files := $(sort $(filter $(apex_dirs), $(INTERNAL_ALLIMAGES_FILES)))
@@ -5079,7 +5082,10 @@
 	@echo $(PRIVATE_APEX_FILES) > /dev/null
 	@rm -rf $(APEX_OUT)
 	@mkdir -p $(APEX_OUT)
-	$< --vendor_path $(TARGET_OUT_VENDOR) \
+	$< --system_path $(TARGET_OUT) \
+	   --system_ext_path $(TARGET_OUT_SYSTEM_EXT) \
+	   --product_path $(TARGET_OUT_PRODUCT) \
+	   --vendor_path $(TARGET_OUT_VENDOR) \
 	   --apex_path $(APEX_OUT)
 
 apex_files :=
@@ -5087,14 +5093,14 @@
 
 # The build system only writes VINTF metadata to */etc/vintf paths. Legacy paths aren't needed here
 # because they are only used for prebuilt images.
-# APEX files in /vendor/apex can have VINTF fragments as well.
+# APEX files in /$partition/apex can have VINTF fragments as well.
 check_vintf_common_srcs_patterns := \
   $(TARGET_OUT)/etc/vintf/% \
   $(TARGET_OUT_VENDOR)/etc/vintf/% \
   $(TARGET_OUT_ODM)/etc/vintf/% \
   $(TARGET_OUT_PRODUCT)/etc/vintf/% \
   $(TARGET_OUT_SYSTEM_EXT)/etc/vintf/% \
-  $(TARGET_OUT_VENDOR)/apex/% \
+  $(apex_dirs)
 
 check_vintf_common_srcs := $(sort $(filter $(check_vintf_common_srcs_patterns),$(INTERNAL_ALLIMAGES_FILES)))
 check_vintf_common_srcs_patterns :=
@@ -5112,15 +5118,17 @@
 # -- Check system and system_ext manifests / matrices including fragments (excluding other framework manifests / matrices, e.g. product);
 ifdef BUILDING_SYSTEM_IMAGE
 check_vintf_system_deps := $(filter $(TARGET_OUT)/etc/vintf/% \
-                                    $(TARGET_OUT_SYSTEM_EXT)/etc/vintf/%, \
+                                    $(TARGET_OUT_SYSTEM_EXT)/etc/vintf/% \
+                                    $(TARGET_OUT)/apex/% \
+                                    $(TARGET_OUT_SYSTEM_EXT)/apex/%, \
                                     $(check_vintf_common_srcs))
 ifneq ($(check_vintf_system_deps),)
 check_vintf_has_system := true
 
 check_vintf_system_log := $(intermediates)/check_vintf_system.log
 check_vintf_all_deps += $(check_vintf_system_log)
-$(check_vintf_system_log): $(HOST_OUT_EXECUTABLES)/checkvintf $(check_vintf_system_deps)
-	@( $< --check-one --dirmap /system:$(TARGET_OUT) > $@ 2>&1 ) || ( cat $@ && exit 1 )
+$(check_vintf_system_log): $(HOST_OUT_EXECUTABLES)/checkvintf $(check_vintf_system_deps) $(APEX_INFO_FILE)
+	@( $< --check-one --dirmap /system:$(TARGET_OUT) --dirmap /apex:$(APEX_OUT) > $@ 2>&1 ) || ( cat $@ && exit 1 )
 $(call declare-1p-target,$(check_vintf_system_log))
 check_vintf_system_log :=
 
@@ -5129,10 +5137,11 @@
     vintffm_log := $(intermediates)/vintffm.log
 endif
 check_vintf_all_deps += $(vintffm_log)
-$(vintffm_log): $(HOST_OUT_EXECUTABLES)/vintffm $(check_vintf_system_deps)
+$(vintffm_log): $(HOST_OUT_EXECUTABLES)/vintffm $(check_vintf_system_deps) $(APEX_INFO_FILE)
 	@( $< --check --dirmap /system:$(TARGET_OUT) \
 	  --dirmap /system_ext:$(TARGET_OUT_SYSTEM_EXT) \
 	  --dirmap /product:$(TARGET_OUT_PRODUCT) \
+	  --dirmap /apex:$(APEX_OUT) \
 	  $(VINTF_FRAMEWORK_MANIFEST_FROZEN_DIR) > $@ 2>&1 ) || ( cat $@ && exit 1 )
 
 $(call declare-1p-target,$(vintffm_log))
diff --git a/tools/aconfig/aconfig_protos/protos/aconfig.proto b/tools/aconfig/aconfig_protos/protos/aconfig.proto
index 8833722..9d1b8cb 100644
--- a/tools/aconfig/aconfig_protos/protos/aconfig.proto
+++ b/tools/aconfig/aconfig_protos/protos/aconfig.proto
@@ -22,16 +22,38 @@
 
 // This protobuf file defines messages used to represent and manage flags in the "aconfig" system
 // The following format requirements apply across various message fields:
-// # name: a lowercase string in snake_case format, no consecutive underscores, and no leading digit
-//    For example adjust_rate is a valid name, while AdjustRate, adjust__rate, and
-//    2adjust_rate are invalid
 //
-// # namespace: a lowercase string in snake_case format, no consecutive underscores, and no leading
-//    digit. For example android_bar_system
+// # name: name of the flag
 //
-// # package: lowercase strings in snake_case format, delimited by dots, no consecutive underscores
-//    and no leading digit in each string. For example com.android.mypackage is a valid name
-//    while com.android.myPackage, com.android.1mypackage are invalid
+//    format: a lowercase string in snake_case format, no consecutive underscores, and no leading
+//      digit. For example adjust_rate is a valid name, while AdjustRate, adjust__rate, and
+//      adjust_rate are invalid
+//
+// # namespace: namespace the flag belongs to
+//
+//    format: a lowercase string in snake_case format, no consecutive underscores, and no leading
+//      digit. For example android_bar_system
+//
+// # package: package to which the flag belongs
+//
+//    format: lowercase strings in snake_case format, delimited by dots, no consecutive underscores
+//      and no leading digit in each string. For example com.android.mypackage is a valid name
+//      while com.android.myPackage, com.android.1mypackage are invalid
+//
+// # container: container as software built in its entirety using the same build environment and
+//    always installed as a single unit
+//
+//    For example the following are all separate containers:
+//        * the system partition
+//        * the vendor partition
+//        * apexes: each APEX is its own container
+//        * APKs: for APKs which are released independently via Play, each APK is its own container.
+//            If an APK is released as part of a Mainline module, or as part of the system partition
+//            via OTA, then they are part of the apex or the system partition container
+//
+//    format: lowercase strings in snake_case format, delimited by dots if multiple, no consecutive
+//      underscores or leading digits in each string. The recommended container values are the
+//      partition names or the module names
 
 // messages used in both aconfig input and output
 
@@ -98,6 +120,7 @@
   repeated flag_declaration flag = 2;
 
   // Container the flag belongs to (optional)
+  // See # container for format detail
   optional string container = 3;
 };
 
@@ -160,6 +183,7 @@
   optional bool is_exported = 10;
 
   // Container the flag belongs to (optional)
+  // See # container for format detail
   optional string container = 11;
 
   // Additional information about the flag, including its purpose and form factors (optional)
diff --git a/tools/aconfig/aflags/src/device_config_source.rs b/tools/aconfig/aflags/src/device_config_source.rs
index 1cea6ed..2589f3d 100644
--- a/tools/aconfig/aflags/src/device_config_source.rs
+++ b/tools/aconfig/aflags/src/device_config_source.rs
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-use crate::{Flag, FlagPermission, FlagSource, ValuePickedFrom};
+use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
 use aconfig_protos::ProtoFlagPermission as ProtoPermission;
 use aconfig_protos::ProtoFlagState as ProtoState;
 use aconfig_protos::ProtoParsedFlag;
@@ -40,10 +40,9 @@
     };
 
     let value = match flag.state() {
-        ProtoState::ENABLED => "true",
-        ProtoState::DISABLED => "false",
-    }
-    .to_string();
+        ProtoState::ENABLED => FlagValue::Enabled,
+        ProtoState::DISABLED => FlagValue::Disabled,
+    };
 
     let permission = match flag.permission() {
         ProtoPermission::READ_ONLY => FlagPermission::ReadOnly,
@@ -86,14 +85,16 @@
     Ok(flags.values().cloned().collect())
 }
 
-fn parse_device_config(raw: &str) -> Result<HashMap<String, String>> {
+fn parse_device_config(raw: &str) -> Result<HashMap<String, FlagValue>> {
     let mut flags = HashMap::new();
     let regex = Regex::new(r"(?m)^([[[:alnum:]]_]+/[[[:alnum:]]_\.]+)=(true|false)$")?;
     for capture in regex.captures_iter(raw) {
         let key =
             capture.get(1).ok_or(anyhow!("invalid device_config output"))?.as_str().to_string();
-        let value = capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str();
-        flags.insert(key, value.to_string());
+        let value = FlagValue::try_from(
+            capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str(),
+        )?;
+        flags.insert(key, value);
     }
     Ok(flags)
 }
@@ -112,24 +113,24 @@
     Ok(str::from_utf8(&output.stdout)?.to_string())
 }
 
-fn read_device_config_flags() -> Result<HashMap<String, String>> {
+fn read_device_config_flags() -> Result<HashMap<String, FlagValue>> {
     let list_output = read_device_config_output(&["list"])?;
     parse_device_config(&list_output)
 }
 
-fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, String>) -> Vec<Flag> {
+fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, FlagValue>) -> Vec<Flag> {
     pb_flags
         .iter()
         .map(|f| {
             dc_flags
                 .get(&format!("{}/{}.{}", f.namespace, f.package, f.name))
                 .map(|value| {
-                    if value.eq(&f.value) {
+                    if *value == f.value {
                         Flag { value_picked_from: ValuePickedFrom::Default, ..f.clone() }
                     } else {
                         Flag {
                             value_picked_from: ValuePickedFrom::Server,
-                            value: value.to_string(),
+                            value: *value,
                             ..f.clone()
                         }
                     }
@@ -167,9 +168,9 @@
 namespace_two/android.flag_two=nonsense
 "#;
         let expected = HashMap::from([
-            ("namespace_one/com.foo.bar.flag_one".to_string(), "true".to_string()),
-            ("namespace_one/com.foo.bar.flag_two".to_string(), "false".to_string()),
-            ("namespace_two/android.flag_one".to_string(), "true".to_string()),
+            ("namespace_one/com.foo.bar.flag_one".to_string(), FlagValue::Enabled),
+            ("namespace_one/com.foo.bar.flag_two".to_string(), FlagValue::Disabled),
+            ("namespace_two/android.flag_one".to_string(), FlagValue::Enabled),
         ]);
         let actual = parse_device_config(input).unwrap();
         assert_eq!(expected, actual);
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index ef0195f..30275e3 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -52,13 +52,40 @@
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+enum FlagValue {
+    Enabled,
+    Disabled,
+}
+
+impl TryFrom<&str> for FlagValue {
+    type Error = anyhow::Error;
+
+    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
+        match value {
+            "true" | "enabled" => Ok(Self::Enabled),
+            "false" | "disabled" => Ok(Self::Disabled),
+            _ => Err(anyhow!("cannot convert string '{}' to FlagValue", value)),
+        }
+    }
+}
+
+impl ToString for FlagValue {
+    fn to_string(&self) -> String {
+        match &self {
+            Self::Enabled => "enabled".into(),
+            Self::Disabled => "disabled".into(),
+        }
+    }
+}
+
 #[derive(Clone)]
 struct Flag {
     namespace: String,
     name: String,
     package: String,
     container: String,
-    value: String,
+    value: FlagValue,
     permission: FlagPermission,
     value_picked_from: ValuePickedFrom,
 }
@@ -116,32 +143,28 @@
 }
 
 struct PaddingInfo {
-    longest_package_col: usize,
-    longest_name_col: usize,
+    longest_flag_col: usize,
     longest_val_col: usize,
     longest_value_picked_from_col: usize,
     longest_permission_col: usize,
 }
 
 fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String {
-    let pkg = &flag.package;
-    let p0 = info.longest_package_col + 1;
-
-    let name = &flag.name;
-    let p1 = info.longest_name_col + 1;
+    let full_name = flag.qualified_name();
+    let p0 = info.longest_flag_col + 1;
 
     let val = flag.value.to_string();
-    let p2 = info.longest_val_col + 1;
+    let p1 = info.longest_val_col + 1;
 
     let value_picked_from = flag.value_picked_from.to_string();
-    let p3 = info.longest_value_picked_from_col + 1;
+    let p2 = info.longest_value_picked_from_col + 1;
 
     let perm = flag.permission.to_string();
-    let p4 = info.longest_permission_col + 1;
+    let p3 = info.longest_permission_col + 1;
 
     let container = &flag.container;
 
-    format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n")
+    format!("{full_name:p0$}{val:p1$}{value_picked_from:p2$}{perm:p3$}{container}\n")
 }
 
 fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
@@ -164,8 +187,7 @@
 fn list() -> Result<String> {
     let flags = DeviceConfigSource::list_flags()?;
     let padding_info = PaddingInfo {
-        longest_package_col: flags.iter().map(|f| f.package.len()).max().unwrap_or(0),
-        longest_name_col: flags.iter().map(|f| f.name.len()).max().unwrap_or(0),
+        longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
         longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
         longest_value_picked_from_col: flags
             .iter()
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index d31f87e..b8dcd84 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -215,7 +215,7 @@
 
   This simulates how apexd activates APEXes.
   1. create {inp}/APEX which is treated as a "/apex" on device.
-  2. invoke apexd_host with vendor APEXes.
+  2. invoke apexd_host with APEXes.
   """
 
   apex_dir = common.MakeTempDir('APEX')
@@ -225,12 +225,13 @@
   # Always create /apex directory for dirmap
   os.makedirs(apex_dir, exist_ok=True)
 
-  # Invoke apexd_host to activate vendor APEXes for checkvintf
+  # Invoke apexd_host to activate APEXes for checkvintf
   apex_host = os.path.join(OPTIONS.search_path, 'bin', 'apexd_host')
   cmd = [apex_host, '--tool_path', OPTIONS.search_path]
   cmd += ['--apex_path', dirmap['/apex']]
-  if '/vendor' in dirmap:
-      cmd += ['--vendor_path', dirmap['/vendor']]
+  for p in ['system', 'system_ext', 'product', 'vendor']:
+    if '/' + p in dirmap:
+      cmd += ['--' + p + '_path', dirmap['/' + p]]
   common.RunAndCheckOutput(cmd)