Merge "Allow map_file_generator to use host tools"
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index d837c6e..252e812 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -140,6 +140,10 @@
                                     $(PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS)
     combined_exclude_paths := $(MEMTAG_HEAP_EXCLUDE_PATHS) \
                               $(PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS)
+    ifneq ($(PRODUCT_MEMTAG_HEAP_SKIP_DEFAULT_PATHS),true)
+      combined_sync_include_paths += $(PRODUCT_MEMTAG_HEAP_SYNC_DEFAULT_INCLUDE_PATHS)
+      combined_async_include_paths += $(PRODUCT_MEMTAG_HEAP_ASYNC_DEFAULT_INCLUDE_PATHS)
+    endif
 
     ifeq ($(strip $(foreach dir,$(subst $(comma),$(space),$(combined_exclude_paths)),\
           $(filter $(dir)%,$(LOCAL_PATH)))),)
diff --git a/core/product.mk b/core/product.mk
index 6f54b78..7e67dcd 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -247,6 +247,16 @@
 # Whether any paths should have HWASan enabled for components
 _product_list_vars += PRODUCT_HWASAN_INCLUDE_PATHS
 
+# Whether any paths should have Memtag_heap enabled for components
+_product_list_vars += PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
+_product_list_vars += PRODUCT_MEMTAG_HEAP_ASYNC_DEFAULT_INCLUDE_PATHS
+_product_list_vars += PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS
+_product_list_vars += PRODUCT_MEMTAG_HEAP_SYNC_DEFAULT_INCLUDE_PATHS
+_product_list_vars += PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS
+
+# Whether this product wants to start with an empty list of default memtag_heap include paths
+_product_single_value_vars += PRODUCT_MEMTAG_HEAP_SKIP_DEFAULT_PATHS
+
 # Whether the Scudo hardened allocator is disabled platform-wide
 _product_single_value_vars += PRODUCT_DISABLE_SCUDO
 
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 6383393..6c613d6 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -116,8 +116,8 @@
 $(call add_json_list, HWASanIncludePaths,                $(HWASAN_INCLUDE_PATHS) $(PRODUCT_HWASAN_INCLUDE_PATHS))
 
 $(call add_json_list, MemtagHeapExcludePaths,            $(MEMTAG_HEAP_EXCLUDE_PATHS) $(PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS))
-$(call add_json_list, MemtagHeapAsyncIncludePaths,       $(MEMTAG_HEAP_ASYNC_INCLUDE_PATHS) $(PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS))
-$(call add_json_list, MemtagHeapSyncIncludePaths,        $(MEMTAG_HEAP_SYNC_INCLUDE_PATHS) $(PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS))
+$(call add_json_list, MemtagHeapAsyncIncludePaths,       $(MEMTAG_HEAP_ASYNC_INCLUDE_PATHS) $(PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS) $(if $(filter true,$(PRODUCT_MEMTAG_HEAP_SKIP_DEFAULT_PATHS)),,$(PRODUCT_MEMTAG_HEAP_ASYNC_DEFAULT_INCLUDE_PATHS)))
+$(call add_json_list, MemtagHeapSyncIncludePaths,       $(MEMTAG_HEAP_SYNC_INCLUDE_PATHS) $(PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS) $(if $(filter true,$(PRODUCT_MEMTAG_HEAP_SKIP_DEFAULT_PATHS)),,$(PRODUCT_MEMTAG_HEAP_SYNC_DEFAULT_INCLUDE_PATHS)))
 
 $(call add_json_bool, DisableScudo,                      $(filter true,$(PRODUCT_DISABLE_SCUDO)))
 
diff --git a/target/product/media_system.mk b/target/product/media_system.mk
index 79bd74a..38ba219 100644
--- a/target/product/media_system.mk
+++ b/target/product/media_system.mk
@@ -76,3 +76,7 @@
 # Enable CFI for security-sensitive components
 $(call inherit-product, $(SRC_TARGET_DIR)/product/cfi-common.mk)
 $(call inherit-product-if-exists, vendor/google/products/cfi-vendor.mk)
+
+# Enable MTE for security-sensitive components
+$(call inherit-product, $(SRC_TARGET_DIR)/product/memtag-common.mk)
+$(call inherit-product-if-exists, vendor/google/products/memtag-vendor.mk)
diff --git a/target/product/memtag-common.mk b/target/product/memtag-common.mk
new file mode 100644
index 0000000..829cb41
--- /dev/null
+++ b/target/product/memtag-common.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2023 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.
+#
+
+# This is a recommended set of common components to enable MTE for.
+
+PRODUCT_MEMTAG_HEAP_ASYNC_DEFAULT_INCLUDE_PATHS := \
+    external/android-clat \
+    external/iproute2 \
+    external/iptables \
+    external/mtpd \
+    external/ppp \
+    hardware/st/nfc \
+    hardware/st/secure_element \
+    hardware/st/secure_element2 \
+    packages/modules/StatsD \
+    system/bpf \
+    system/netd/netutil_wrappers \
+    system/netd/server
diff --git a/target/product/module_common.mk b/target/product/module_common.mk
index 84bd799..53b2ca6 100644
--- a/target/product/module_common.mk
+++ b/target/product/module_common.mk
@@ -17,6 +17,7 @@
 $(call inherit-product, $(SRC_TARGET_DIR)/product/default_art_config.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/languages_default.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/cfi-common.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/memtag-common.mk)
 
 # Enables treble, which enabled certain -D compilation flags. In particular, libhidlbase
 # uses -DENFORCE_VINTF_MANIFEST. See b/185759877
diff --git a/tools/aconfig/src/codegen.rs b/tools/aconfig/src/codegen.rs
index fea9961..d96d4f9 100644
--- a/tools/aconfig/src/codegen.rs
+++ b/tools/aconfig/src/codegen.rs
@@ -17,7 +17,10 @@
 use anyhow::{ensure, Result};
 
 pub fn is_valid_name_ident(s: &str) -> bool {
-    // Identifiers must match [a-z][a-z0-9_]*
+    // Identifiers must match [a-z][a-z0-9_]*, except consecutive underscores are not allowed
+    if s.contains("__") {
+        return false;
+    }
     let mut chars = s.chars();
     let Some(first) = chars.next() else {
         return false;
@@ -46,11 +49,14 @@
     fn test_is_valid_name_ident() {
         assert!(is_valid_name_ident("foo"));
         assert!(is_valid_name_ident("foo_bar_123"));
+        assert!(is_valid_name_ident("foo_"));
 
         assert!(!is_valid_name_ident(""));
         assert!(!is_valid_name_ident("123_foo"));
         assert!(!is_valid_name_ident("foo-bar"));
         assert!(!is_valid_name_ident("foo-b\u{00e5}r"));
+        assert!(!is_valid_name_ident("foo__bar"));
+        assert!(!is_valid_name_ident("_foo"));
     }
 
     #[test]
@@ -59,6 +65,7 @@
         assert!(is_valid_package_ident("foo_bar_123"));
         assert!(is_valid_package_ident("foo.bar"));
         assert!(is_valid_package_ident("foo.bar.a123"));
+        assert!(!is_valid_package_ident("foo._bar"));
 
         assert!(!is_valid_package_ident(""));
         assert!(!is_valid_package_ident("123_foo"));
@@ -69,6 +76,7 @@
         assert!(!is_valid_package_ident("foo.bar."));
         assert!(!is_valid_package_ident("."));
         assert!(!is_valid_package_ident("foo..bar"));
+        assert!(!is_valid_package_ident("foo.__bar"));
     }
 
     #[test]
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();
+
+}