Merge "Remove --blkid_path argument"
diff --git a/core/Makefile b/core/Makefile
index e2c5900..6dbbef1 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -5886,14 +5886,25 @@
     echo "virtual_ab_cow_version=$(PRODUCT_VIRTUAL_AB_COW_VERSION)" >> $(1))
 endef
 
-# Copy an image file to a directory and generate a block list map file from the image.
+# Copy an image file to a directory and generate a block list map file from the image,
+# only if the map_file_generator supports the file system.
+# Otherwise, skip generating map files as well as copying images. The image will be
+# generated from the $(ADD_IMG_TO_TARGET_FILES) to generate the map file with it.
 # $(1): path of the image file
 # $(2): target out directory
-# $(3): name of the map file. skip generating map file if empty
+# $(3): image name to generate a map file. skip generating map file if empty
 define copy-image-and-generate-map
-  mkdir -p $(2)
-  cp $(1) $(2)
-  $(if $(3),$(HOST_OUT_EXECUTABLES)/map_file_generator $(1) $(2)/$(3))
+  $(eval _supported_fs_for_map_file_generator := erofs ext%)
+  $(eval _img := $(call to-upper,$(3)))
+  $(if $(3),$(eval _map_fs_type := $(BOARD_$(_img)IMAGE_FILE_SYSTEM_TYPE)),\
+    $(eval _no_map_file := "true"))
+  $(if $(filter $(_supported_fs_for_map_file_generator),$(_map_fs_type))$(_no_map_file),\
+    mkdir -p $(2); \
+    cp $(1) $(2); \
+    $(if $(3),$(HOST_OUT_EXECUTABLES)/map_file_generator $(1) $(2)/$(3).map))
+  $(eval _img :=)
+  $(eval _map_fs_type :=)
+  $(eval _no_map_file :=)
 endef
 
 # By conditionally including the dependency of the target files package on the
@@ -6405,35 +6416,35 @@
 	@# Run fs_config on all the system, vendor, boot ramdisk,
 	@# and recovery ramdisk files in the zip, and save the output
 ifdef BUILDING_SYSTEM_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEMIMAGE),$(zip_root)/IMAGES,system.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEMIMAGE),$(zip_root)/IMAGES,system)
 	$(hide) $(call fs_config,$(zip_root)/SYSTEM,system/) > $(zip_root)/META/filesystem_config.txt
 endif
 ifdef BUILDING_VENDOR_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_VENDORIMAGE_TARGET),$(zip_root)/IMAGES,vendor.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_VENDORIMAGE_TARGET),$(zip_root)/IMAGES,vendor)
 	$(hide) $(call fs_config,$(zip_root)/VENDOR,vendor/) > $(zip_root)/META/vendor_filesystem_config.txt
 endif
 ifdef BUILDING_PRODUCT_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_PRODUCTIMAGE_TARGET),$(zip_root)/IMAGES,product.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_PRODUCTIMAGE_TARGET),$(zip_root)/IMAGES,product)
 	$(hide) $(call fs_config,$(zip_root)/PRODUCT,product/) > $(zip_root)/META/product_filesystem_config.txt
 endif
 ifdef BUILDING_SYSTEM_EXT_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEM_EXTIMAGE_TARGET),$(zip_root)/IMAGES,system_ext.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEM_EXTIMAGE_TARGET),$(zip_root)/IMAGES,system_ext)
 	$(hide) $(call fs_config,$(zip_root)/SYSTEM_EXT,system_ext/) > $(zip_root)/META/system_ext_filesystem_config.txt
 endif
 ifdef BUILDING_ODM_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_ODMIMAGE_TARGET),$(zip_root)/IMAGES,odm.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_ODMIMAGE_TARGET),$(zip_root)/IMAGES,odm)
 	$(hide) $(call fs_config,$(zip_root)/ODM,odm/) > $(zip_root)/META/odm_filesystem_config.txt
 endif
 ifdef BUILDING_VENDOR_DLKM_IMAGE
-	$(hide)$(call copy-image-and-generate-map,$(BUILT_VENDOR_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,vendor_dlkm.map)
+	$(hide)$(call copy-image-and-generate-map,$(BUILT_VENDOR_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,vendor_dlkm)
 	$(hide) $(call fs_config,$(zip_root)/VENDOR_DLKM,vendor_dlkm/) > $(zip_root)/META/vendor_dlkm_filesystem_config.txt
 endif
 ifdef BUILDING_ODM_DLKM_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_ODM_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,odm_dlkm.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_ODM_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,odm_dlkm)
 	$(hide) $(call fs_config,$(zip_root)/ODM_DLKM,odm_dlkm/) > $(zip_root)/META/odm_dlkm_filesystem_config.txt
 endif
 ifdef BUILDING_SYSTEM_DLKM_IMAGE
-	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEM_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,system_dlkm.map)
+	$(hide) $(call copy-image-and-generate-map,$(BUILT_SYSTEM_DLKMIMAGE_TARGET),$(zip_root)/IMAGES,system_dlkm)
 	$(hide) $(call fs_config,$(zip_root)/SYSTEM_DLKM,system_dlkm/) > $(zip_root)/META/system_dlkm_filesystem_config.txt
 endif
 	@# ROOT always contains the files for the root under normal boot.
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index 2df85e5..c747d89 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -4,6 +4,7 @@
 LLNDK: libGLESv3.so
 LLNDK: libRS.so
 LLNDK: libandroid_net.so
+LLNDK: libapexsupport.so
 LLNDK: libbinder_ndk.so
 LLNDK: libc.so
 LLNDK: libcgrouprc.so
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index cf025cb..54fa0dc 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -24,43 +24,59 @@
 use crate::codegen;
 use crate::commands::OutputFile;
 
-pub fn generate_java_code(cache: &Cache) -> Result<OutputFile> {
+pub fn generate_java_code(cache: &Cache) -> Result<Vec<OutputFile>> {
     let package = cache.package();
     let class_elements: Vec<ClassElement> =
         cache.iter().map(|item| create_class_element(package, item)).collect();
-    let readwrite = class_elements.iter().any(|item| item.readwrite);
-    let context = Context { package: package.to_string(), readwrite, class_elements };
+    let is_read_write = class_elements.iter().any(|item| item.is_read_write);
+    let context = Context { package_name: package.to_string(), is_read_write, class_elements };
+
+    let java_files = vec!["Flags.java", "FeatureFlagsImpl.java", "FeatureFlags.java"];
+
     let mut template = TinyTemplate::new();
-    template.add_template("java_code_gen", include_str!("../templates/java.template"))?;
-    let contents = template.render("java_code_gen", &context)?;
-    let mut path: PathBuf = package.split('.').collect();
-    // TODO: Allow customization of the java class name
-    path.push("Flags.java");
-    Ok(OutputFile { contents: contents.into(), path })
+    template.add_template("Flags.java", include_str!("../templates/Flags.java.template"))?;
+    template.add_template(
+        "FeatureFlagsImpl.java",
+        include_str!("../templates/FeatureFlagsImpl.java.template"),
+    )?;
+    template.add_template(
+        "FeatureFlags.java",
+        include_str!("../templates/FeatureFlags.java.template"),
+    )?;
+
+    let path: PathBuf = package.split('.').collect();
+    java_files
+        .iter()
+        .map(|file| {
+            Ok(OutputFile {
+                contents: template.render(file, &context)?.into(),
+                path: path.join(file),
+            })
+        })
+        .collect::<Result<Vec<OutputFile>>>()
 }
 
 #[derive(Serialize)]
 struct Context {
-    pub package: String,
-    pub readwrite: bool,
+    pub package_name: String,
+    pub is_read_write: bool,
     pub class_elements: Vec<ClassElement>,
 }
 
 #[derive(Serialize)]
 struct ClassElement {
-    pub method_name: String,
-    pub readwrite: bool,
     pub default_value: String,
     pub device_config_namespace: String,
     pub device_config_flag: String,
+    pub flag_name_constant_suffix: String,
+    pub is_read_write: bool,
+    pub method_name: String,
 }
 
 fn create_class_element(package: &str, item: &Item) -> ClassElement {
     let device_config_flag = codegen::create_device_config_ident(package, &item.name)
         .expect("values checked at cache creation time");
     ClassElement {
-        method_name: item.name.replace('-', "_"),
-        readwrite: item.permission == Permission::ReadWrite,
         default_value: if item.state == FlagState::Enabled {
             "true".to_string()
         } else {
@@ -68,78 +84,100 @@
         },
         device_config_namespace: item.namespace.clone(),
         device_config_flag,
+        flag_name_constant_suffix: item.name.to_ascii_uppercase(),
+        is_read_write: item.permission == Permission::ReadWrite,
+        method_name: item.name.clone(),
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::aconfig::{FlagDeclaration, FlagValue};
-    use crate::cache::CacheBuilder;
-    use crate::commands::Source;
+    use std::collections::HashMap;
 
     #[test]
     fn test_generate_java_code() {
-        let package = "com.example";
-        let mut builder = CacheBuilder::new(package.to_string()).unwrap();
-        builder
-            .add_flag_declaration(
-                Source::File("test.txt".to_string()),
-                FlagDeclaration {
-                    name: "test".to_string(),
-                    namespace: "ns".to_string(),
-                    description: "buildtime enable".to_string(),
-                },
-            )
-            .unwrap()
-            .add_flag_declaration(
-                Source::File("test2.txt".to_string()),
-                FlagDeclaration {
-                    name: "test2".to_string(),
-                    namespace: "ns".to_string(),
-                    description: "runtime disable".to_string(),
-                },
-            )
-            .unwrap()
-            .add_flag_value(
-                Source::Memory,
-                FlagValue {
-                    package: package.to_string(),
-                    name: "test".to_string(),
-                    state: FlagState::Disabled,
-                    permission: Permission::ReadOnly,
-                },
-            )
-            .unwrap();
-        let cache = builder.build();
-        let expect_content = r#"package com.example;
-
-        import android.provider.DeviceConfig;
-
+        let cache = crate::test::create_cache();
+        let generated_files = generate_java_code(&cache).unwrap();
+        let expect_flags_content = r#"
+        package com.android.aconfig.test;
         public final class Flags {
-
-            public static boolean test() {
-                return false;
+            public static boolean disabled_ro() {
+                return FEATURE_FLAGS.disabled_ro();
             }
-
-            public static boolean test2() {
-                return DeviceConfig.getBoolean(
-                    "ns",
-                    "com.example.test2",
-                    false
-                );
+            public static boolean disabled_rw() {
+                return FEATURE_FLAGS.disabled_rw();
             }
+            public static boolean enabled_ro() {
+                return FEATURE_FLAGS.enabled_ro();
+            }
+            public static boolean enabled_rw() {
+                return FEATURE_FLAGS.enabled_rw();
+            }
+            private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
 
         }
         "#;
-        let file = generate_java_code(&cache).unwrap();
-        assert_eq!("com/example/Flags.java", file.path.to_str().unwrap());
-        assert_eq!(
-            None,
-            crate::test::first_significant_code_diff(
-                expect_content,
-                &String::from_utf8(file.contents).unwrap()
-            )
-        );
+        let expected_featureflagsimpl_content = r#"
+        package com.android.aconfig.test;
+        import android.provider.DeviceConfig;
+        public final class FeatureFlagsImpl implements FeatureFlags {
+            @Override
+            public boolean disabled_ro() {
+                return false;
+            }
+            @Override
+            public boolean disabled_rw() {
+                return DeviceConfig.getBoolean(
+                    "aconfig_test",
+                    "com.android.aconfig.test.disabled_rw",
+                    false
+                );
+            }
+            @Override
+            public boolean enabled_ro() {
+                return true;
+            }
+            @Override
+            public boolean enabled_rw() {
+                return DeviceConfig.getBoolean(
+                    "aconfig_test",
+                    "com.android.aconfig.test.enabled_rw",
+                    true
+                );
+            }
+        }
+        "#;
+        let expected_featureflags_content = r#"
+        package com.android.aconfig.test;
+        public interface FeatureFlags {
+            boolean disabled_ro();
+            boolean disabled_rw();
+            boolean enabled_ro();
+            boolean enabled_rw();
+        }
+        "#;
+        let mut file_set = HashMap::from([
+            ("com/android/aconfig/test/Flags.java", expect_flags_content),
+            ("com/android/aconfig/test/FeatureFlagsImpl.java", expected_featureflagsimpl_content),
+            ("com/android/aconfig/test/FeatureFlags.java", expected_featureflags_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.clone()).unwrap()
+                ),
+                "File {} content is not correct",
+                file_path
+            );
+            file_set.remove(file_path);
+        }
+
+        assert!(file_set.is_empty());
     }
 }
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index 586ba04..eb860b0 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -89,7 +89,7 @@
     Ok(builder.build())
 }
 
-pub fn create_java_lib(cache: Cache) -> Result<OutputFile> {
+pub fn create_java_lib(cache: Cache) -> Result<Vec<OutputFile>> {
     generate_java_code(&cache)
 }
 
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index 5a820d9..3a9a573 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -147,8 +147,10 @@
             let file = fs::File::open(path)?;
             let cache = Cache::read_from_reader(file)?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
-            let generated_file = commands::create_java_lib(cache)?;
-            write_output_file_realtive_to_dir(&dir, &generated_file)?;
+            let generated_files = commands::create_java_lib(cache)?;
+            generated_files
+                .iter()
+                .try_for_each(|file| write_output_file_realtive_to_dir(&dir, file))?;
         }
         Some(("create-cpp-lib", sub_matches)) => {
             let path = get_required_arg::<String>(sub_matches, "cache")?;
diff --git a/tools/aconfig/templates/FeatureFlags.java.template b/tools/aconfig/templates/FeatureFlags.java.template
new file mode 100644
index 0000000..b9e2cc7
--- /dev/null
+++ b/tools/aconfig/templates/FeatureFlags.java.template
@@ -0,0 +1,7 @@
+package {package_name};
+
+public interface FeatureFlags \{
+    {{ for item in class_elements}}
+    boolean {item.method_name}();
+    {{ endfor }}
+}
\ No newline at end of file
diff --git a/tools/aconfig/templates/java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
similarity index 63%
rename from tools/aconfig/templates/java.template
rename to tools/aconfig/templates/FeatureFlagsImpl.java.template
index a3d3319..2b031f1 100644
--- a/tools/aconfig/templates/java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,11 +1,12 @@
-package {package};
-{{ if readwrite }}
+package {package_name};
+{{ if is_read_write }}
 import android.provider.DeviceConfig;
 {{ endif }}
-public final class Flags \{
+public final class FeatureFlagsImpl implements FeatureFlags \{
     {{ for item in class_elements}}
-    public static boolean {item.method_name}() \{
-        {{ if item.readwrite- }}
+    @Override
+    public boolean {item.method_name}() \{
+        {{ if item.is_read_write- }}
         return DeviceConfig.getBoolean(
             "{item.device_config_namespace}",
             "{item.device_config_flag}",
@@ -16,4 +17,4 @@
         {{ -endif }}
     }
     {{ endfor }}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/templates/Flags.java.template b/tools/aconfig/templates/Flags.java.template
new file mode 100644
index 0000000..752a469
--- /dev/null
+++ b/tools/aconfig/templates/Flags.java.template
@@ -0,0 +1,11 @@
+package {package_name};
+
+public final class Flags \{
+    {{ for item in class_elements}}
+    public static boolean {item.method_name}() \{
+        return FEATURE_FLAGS.{item.method_name}();
+    }
+    {{ endfor }}
+    private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+
+}
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index f92d67c..d33397b 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -2126,17 +2126,28 @@
   """
   with zipfile.ZipFile(filename, allowZip64=True, mode="r") as input_zip:
     # Filter out non-matching patterns. unzip will complain otherwise.
+    entries = input_zip.infolist()
+    # b/283033491
+    # Per https://en.wikipedia.org/wiki/ZIP_(file_format)#Central_directory_file_header
+    # In zip64 mode, central directory record's header_offset field might be
+    # set to 0xFFFFFFFF if header offset is > 2^32. In this case, the extra
+    # fields will contain an 8 byte little endian integer at offset 20
+    # to indicate the actual local header offset.
+    # As of python3.11, python does not handle zip64 central directories
+    # correctly, so we will manually do the parsing here.
+    for entry in entries:
+      if entry.header_offset == 0xFFFFFFFF and len(entry.extra) >= 28:
+        entry.header_offset = int.from_bytes(entry.extra[20:28], "little")
     if patterns is not None:
-      names = input_zip.namelist()
-      filtered = [name for name in names if any(
-          [fnmatch.fnmatch(name, p) for p in patterns])]
+      filtered = [info for info in entries if any(
+          [fnmatch.fnmatch(info.filename, p) for p in patterns])]
 
       # There isn't any matching files. Don't unzip anything.
       if not filtered:
         return
       input_zip.extractall(dirname, filtered)
     else:
-      input_zip.extractall(dirname)
+      input_zip.extractall(dirname, entries)
 
 
 def UnzipTemp(filename, patterns=None):
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 466cafb..68c6887 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -762,6 +762,9 @@
   path = os.path.join(target_files_dir, "RADIO", partition + ".map")
   if os.path.exists(path):
     return path
+  path = os.path.join(target_files_dir, "IMAGES", partition + ".map")
+  if os.path.exists(path):
+    return path
   return ""