Merge "aconfig: add a storage file read api to get file version number" into main
diff --git a/core/Makefile b/core/Makefile
index 2165700..f132db3 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -6082,7 +6082,7 @@
 # $1: root directory
 # $2: add prefix
 define fs_config
-(cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) -R "$(2)"
+(cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -R "$(2)"
 endef
 
 define filter-out-missing-vendor
diff --git a/core/binary.mk b/core/binary.mk
index 6dab49c..b17ab00 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -481,6 +481,34 @@
     my_cflags += $(CLANG_EXTERNAL_CFLAGS)
 endif
 
+# Extra cflags for projects under hardware/ directory.
+# This should match the definition of `thirdPartyDirPrefixExceptions`
+# in build/soong/android/paths.go.
+# Get the second element of LOCAL_PATH
+ifneq ($(filter hardware/%,$(LOCAL_PATH)),)
+  my_subdir := $(word 2,$(subst /,$(space),$(LOCAL_PATH)))
+  must_compile_hardware_subdirs := \
+                  hardware/google/% \
+                  hardware/interfaces/% \
+                  hardware/libhardware/% \
+                  hardware/libhardware_legacy/% \
+                  hardware/ril/%
+  ifeq ($(filter $(must_compile_hardware_subdirs),$(my_subdir)),)
+    my_cflags += $(CLANG_EXTERNAL_CFLAGS)
+  endif
+endif
+
+# Extra cflags for projects under vendor/ directory.
+# This should match the definition of `thirdPartyDirPrefixExceptions`
+# in build/soong/android/paths.go.
+ifneq ($(filter vendor/%,$(LOCAL_PATH)),)
+  my_subdir := $(word 2,$(subst /,$(space),$(LOCAL_PATH)))
+  # Do not add the flags for any subdir that contains the string "google".
+  ifneq ($(findstring google,$(my_subdir)),)
+    my_cflags += $(CLANG_EXTERNAL_CFLAGS)
+  endif
+endif
+
 # arch-specific static libraries go first so that generic ones can depend on them
 my_static_libraries := $(LOCAL_STATIC_LIBRARIES_$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)) $(LOCAL_STATIC_LIBRARIES_$(my_32_64_bit_suffix)) $(my_static_libraries)
 my_whole_static_libraries := $(LOCAL_WHOLE_STATIC_LIBRARIES_$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)) $(LOCAL_WHOLE_STATIC_LIBRARIES_$(my_32_64_bit_suffix)) $(my_whole_static_libraries)
diff --git a/core/product_config.mk b/core/product_config.mk
index 500735e..4525423 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -606,6 +606,15 @@
 endif
 endef
 
+ifndef PRODUCT_VIRTUAL_AB_COW_VERSION
+  PRODUCT_VIRTUAL_AB_COW_VERSION := 2
+  ifdef PRODUCT_SHIPPING_API_LEVEL
+    ifeq (true,$(call math_gt_or_eq,$(PRODUCT_SHIPPING_API_LEVEL),34))
+      PRODUCT_VIRTUAL_AB_COW_VERSION := 3
+    endif
+  endif
+endif
+
 # Copy and check the value of each PRODUCT_BUILD_*_IMAGE variable
 $(foreach image, \
     PVMFW \
diff --git a/target/product/virtual_ab_ota/android_t_baseline.mk b/target/product/virtual_ab_ota/android_t_baseline.mk
index af0f7a9..418aaa4 100644
--- a/target/product/virtual_ab_ota/android_t_baseline.mk
+++ b/target/product/virtual_ab_ota/android_t_baseline.mk
@@ -20,5 +20,3 @@
 #
 # All U+ launching devices should instead use vabc_features.mk.
 $(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)
-
-PRODUCT_VIRTUAL_AB_COW_VERSION ?= 2
diff --git a/tools/aconfig/aconfig/Android.bp b/tools/aconfig/aconfig/Android.bp
index 2c26166..00a6fee 100644
--- a/tools/aconfig/aconfig/Android.bp
+++ b/tools/aconfig/aconfig/Android.bp
@@ -47,6 +47,7 @@
 aconfig_declarations {
     name: "aconfig.test.exported.flags",
     package: "com.android.aconfig.test.exported",
+    exportable: true,
     container: "system",
     srcs: ["tests/test_exported.aconfig"],
 }
diff --git a/tools/aconfig/aflags/src/device_config_source.rs b/tools/aconfig/aflags/src/device_config_source.rs
index 12a62cf..1cea6ed 100644
--- a/tools/aconfig/aflags/src/device_config_source.rs
+++ b/tools/aconfig/aflags/src/device_config_source.rs
@@ -64,7 +64,7 @@
 fn read_pb_files() -> Result<Vec<Flag>> {
     let mut flags: BTreeMap<String, Flag> = BTreeMap::new();
     for partition in ["system", "system_ext", "product", "vendor"] {
-        let path = format!("/{}/etc/aconfig_flags.pb", partition);
+        let path = format!("/{partition}/etc/aconfig_flags.pb");
         let Ok(bytes) = fs::read(&path) else {
             eprintln!("warning: failed to read {}", path);
             continue;
@@ -98,11 +98,13 @@
     Ok(flags)
 }
 
-fn read_device_config_output(command: &str) -> Result<String> {
-    let output = Command::new("/system/bin/device_config").arg(command).output()?;
+fn read_device_config_output(command: &[&str]) -> Result<String> {
+    let output = Command::new("/system/bin/device_config").args(command).output()?;
     if !output.status.success() {
         let reason = match output.status.code() {
-            Some(code) => format!("exit code {}", code),
+            Some(code) => {
+                format!("exit code {}, output was {}", code, str::from_utf8(&output.stdout)?)
+            }
             None => "terminated by signal".to_string(),
         };
         bail!("failed to execute device_config: {}", reason);
@@ -111,7 +113,7 @@
 }
 
 fn read_device_config_flags() -> Result<HashMap<String, String>> {
-    let list_output = read_device_config_output("list")?;
+    let list_output = read_device_config_output(&["list"])?;
     parse_device_config(&list_output)
 }
 
@@ -145,6 +147,10 @@
         let flags = reconcile(&pb_flags, dc_flags);
         Ok(flags)
     }
+
+    fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()> {
+        read_device_config_output(&["put", namespace, qualified_name, value]).map(|_| ())
+    }
 }
 
 #[cfg(test)]
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index 1e2a7a0..ef0195f 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -16,7 +16,7 @@
 
 //! `aflags` is a device binary to read and write aconfig flags.
 
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use clap::Parser;
 
 mod device_config_source;
@@ -63,8 +63,15 @@
     value_picked_from: ValuePickedFrom,
 }
 
+impl Flag {
+    fn qualified_name(&self) -> String {
+        format!("{}.{}", self.package, self.name)
+    }
+}
+
 trait FlagSource {
     fn list_flags() -> Result<Vec<Flag>>;
+    fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
 }
 
 const ABOUT_TEXT: &str = "Tool for reading and writing flags.
@@ -94,6 +101,18 @@
 enum Command {
     /// List all aconfig flags on this device.
     List,
+
+    /// Enable an aconfig flag on this device, on the next boot.
+    Enable {
+        /// <package>.<flag_name>
+        qualified_name: String,
+    },
+
+    /// Disable an aconfig flag on this device, on the next boot.
+    Disable {
+        /// <package>.<flag_name>
+        qualified_name: String,
+    },
 }
 
 struct PaddingInfo {
@@ -125,6 +144,23 @@
     format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n")
 }
 
+fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
+    let flags_binding = DeviceConfigSource::list_flags()?;
+    let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or(
+        anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"),
+    )?;
+
+    if let FlagPermission::ReadOnly = flag.permission {
+        return Err(anyhow!(
+            "could not write flag '{qualified_name}', it is read-only for the current release configuration.",
+        ));
+    }
+
+    DeviceConfigSource::override_flag(&flag.namespace, qualified_name, value)?;
+
+    Ok(())
+}
+
 fn list() -> Result<String> {
     let flags = DeviceConfigSource::list_flags()?;
     let padding_info = PaddingInfo {
@@ -154,10 +190,13 @@
 fn main() {
     let cli = Cli::parse();
     let output = match cli.command {
-        Command::List => list(),
+        Command::List => list().map(Some),
+        Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
+        Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
     };
     match output {
-        Ok(text) => println!("{text}"),
-        Err(msg) => println!("Error: {}", msg),
+        Ok(Some(text)) => println!("{text}"),
+        Ok(None) => (),
+        Err(message) => println!("Error: {message}"),
     }
 }
diff --git a/tools/fs_config/Android.bp b/tools/fs_config/Android.bp
index 55fdca4..bd9543a 100644
--- a/tools/fs_config/Android.bp
+++ b/tools/fs_config/Android.bp
@@ -35,7 +35,6 @@
     srcs: ["fs_config.c"],
     shared_libs: [
         "libcutils",
-        "libselinux",
     ],
     cflags: ["-Werror"],
 }
diff --git a/tools/fs_config/fs_config.c b/tools/fs_config/fs_config.c
index 2a75add..80bd3c1 100644
--- a/tools/fs_config/fs_config.c
+++ b/tools/fs_config/fs_config.c
@@ -22,9 +22,6 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
 #include "private/android_filesystem_config.h"
 #include "private/fs_config.h"
 
@@ -35,8 +32,8 @@
 //
 // After the first 4 columns, optional key=value pairs are emitted
 // for each file.  Currently, the following keys are supported:
-// * -S: selabel=[selinux_label]
-// * -C: capabilities=[hex capabilities value]
+//
+//   -C: capabilities=[hex capabilities value]
 //
 // Example input:
 //
@@ -48,45 +45,24 @@
 //      system/etc/dbus.conf 1002 1002 440
 //      data/app 1000 1000 771
 //
-//   or if, for example, -S is used:
-//
-//      system/etc/dbus.conf 1002 1002 440 selabel=u:object_r:system_file:s0
-//      data/app 1000 1000 771 selabel=u:object_r:apk_data_file:s0
-//
 // Note that the output will omit the trailing slash from
 // directories.
 
-static struct selabel_handle* get_sehnd(const char* context_file) {
-  struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, context_file } };
-  struct selabel_handle* sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
-
-  if (!sehnd) {
-    perror("error running selabel_open");
-    exit(EXIT_FAILURE);
-  }
-  return sehnd;
-}
-
 static void usage() {
-  fprintf(stderr, "Usage: fs_config [-D product_out_path] [-S context_file] [-R root] [-C]\n");
+  fprintf(stderr, "Usage: fs_config [-D product_out_path] [-R root] [-C]\n");
 }
 
 int main(int argc, char** argv) {
   char buffer[1024];
-  const char* context_file = NULL;
   const char* product_out_path = NULL;
   char* root_path = NULL;
-  struct selabel_handle* sehnd = NULL;
   int print_capabilities = 0;
   int opt;
-  while((opt = getopt(argc, argv, "CS:R:D:")) != -1) {
+  while((opt = getopt(argc, argv, "CR:D:")) != -1) {
     switch(opt) {
     case 'C':
       print_capabilities = 1;
       break;
-    case 'S':
-      context_file = optarg;
-      break;
     case 'R':
       root_path = optarg;
       break;
@@ -99,10 +75,6 @@
     }
   }
 
-  if (context_file != NULL) {
-    sehnd = get_sehnd(context_file);
-  }
-
   if (root_path != NULL) {
     size_t root_len = strlen(root_path);
     /* Trim any trailing slashes from the root path. */
@@ -141,33 +113,6 @@
     }
     printf("%s %d %d %o", buffer, uid, gid, mode);
 
-    if (sehnd != NULL) {
-      size_t buffer_strlen = strnlen(buffer, sizeof(buffer));
-      if (buffer_strlen >= sizeof(buffer)) {
-        fprintf(stderr, "non null terminated buffer, aborting\n");
-        exit(EXIT_FAILURE);
-      }
-      size_t full_name_size = buffer_strlen + 2;
-      char* full_name = (char*) malloc(full_name_size);
-      if (full_name == NULL) {
-        perror("malloc");
-        exit(EXIT_FAILURE);
-      }
-
-      full_name[0] = '/';
-      strncpy(full_name + 1, buffer, full_name_size - 1);
-      full_name[full_name_size - 1] = '\0';
-
-      char* secontext;
-      if (selabel_lookup(sehnd, &secontext, full_name, ( mode | (is_dir ? S_IFDIR : S_IFREG)))) {
-        secontext = strdup("u:object_r:unlabeled:s0");
-      }
-
-      printf(" selabel=%s", secontext);
-      free(full_name);
-      freecon(secontext);
-    }
-
     if (print_capabilities) {
       printf(" capabilities=0x%" PRIx64, capabilities);
     }