Merge "BOARD_VNDK_VERSION must be set first pass"
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 6ba539c..5dba2d1 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -154,6 +154,10 @@
 $(call add_soong_config_var_value,ANDROID,avf_enabled,$(PRODUCT_AVF_ENABLED))
 endif
 
+ifdef PRODUCT_AVF_KERNEL_MODULES_ENABLED
+$(call add_soong_config_var_value,ANDROID,avf_kernel_modules_enabled,$(PRODUCT_AVF_KERNEL_MODULES_ENABLED))
+endif
+
 # Enable system_server optimizations by default unless explicitly set or if
 # there may be dependent runtime jars.
 # TODO(b/240588226): Remove the off-by-default exceptions after handling
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index aa638d4..d837c6e 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -249,6 +249,13 @@
   endif
 endif
 
+# Ignore SANITIZE_TARGET_DIAG=memtag_heap without SANITIZE_TARGET=memtag_heap
+# This can happen if a condition above filters out memtag_heap from
+# my_sanitize. It is easier to handle all of these cases here centrally.
+ifneq ($(filter memtag_heap,$(my_sanitize_diag)),)
+  my_sanitize_diag := $(filter-out memtag_heap,$(my_sanitize_diag))
+endif
+
 ifneq ($(filter memtag_heap,$(my_sanitize)),)
   my_cflags += -fsanitize=memtag-heap
   my_sanitize := $(filter-out memtag_heap,$(my_sanitize))
diff --git a/core/product.mk b/core/product.mk
index 818aac2..6f54b78 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -389,6 +389,9 @@
 # If true, installs a full version of com.android.virt APEX.
 _product_single_value_vars += PRODUCT_AVF_ENABLED
 
+# If true, kernel with modules will be used for Microdroid VMs.
+_product_single_value_vars += PRODUCT_AVF_KERNEL_MODULES_ENABLED
+
 # List of .json files to be merged/compiled into vendor/etc/linker.config.pb
 _product_list_vars += PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS
 
diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk
index 41233b2..d965367 100644
--- a/target/product/handheld_system.mk
+++ b/target/product/handheld_system.mk
@@ -27,6 +27,7 @@
 $(call inherit-product-if-exists, external/google-fonts/source-sans-pro/fonts.mk)
 $(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
 $(call inherit-product-if-exists, external/roboto-fonts/fonts.mk)
+$(call inherit-product-if-exists, external/roboto-flex-fonts/fonts.mk)
 $(call inherit-product-if-exists, external/hyphenation-patterns/patterns.mk)
 $(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
 $(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 9617e0e..b8cce29 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -35,4 +35,7 @@
 rust_test_host {
     name: "aconfig.test",
     defaults: ["aconfig.defaults"],
+    rustlibs: [
+        "libitertools",
+    ],
 }
diff --git a/tools/aconfig/Cargo.toml b/tools/aconfig/Cargo.toml
index 8517dd2..b3c73b8 100644
--- a/tools/aconfig/Cargo.toml
+++ b/tools/aconfig/Cargo.toml
@@ -18,3 +18,6 @@
 
 [build-dependencies]
 protobuf-codegen = "3.2.0"
+
+[dev-dependencies]
+itertools = "0.10.5"
diff --git a/tools/aconfig/protos/aconfig.proto b/tools/aconfig/protos/aconfig.proto
index 9d36a9e..9f6424f 100644
--- a/tools/aconfig/protos/aconfig.proto
+++ b/tools/aconfig/protos/aconfig.proto
@@ -36,16 +36,17 @@
 
 message flag_declaration {
   required string name = 1;
-  required string description = 2;
+  required string namespace = 2;
+  required string description = 3;
 };
 
 message flag_declarations {
-  required string namespace = 1;
+  required string package = 1;
   repeated flag_declaration flag = 2;
 };
 
 message flag_value {
-  required string namespace = 1;
+  required string package = 1;
   required string name = 2;
   required flag_state state = 3;
   required flag_permission permission = 4;
@@ -65,12 +66,13 @@
 }
 
 message parsed_flag {
-  required string namespace = 1;
+  required string package = 1;
   required string name = 2;
-  required string description = 3;
-  required flag_state state = 4;
-  required flag_permission permission = 5;
-  repeated tracepoint trace = 6;
+  required string namespace = 3;
+  required string description = 4;
+  required flag_state state = 5;
+  required flag_permission permission = 6;
+  repeated tracepoint trace = 7;
 }
 
 message parsed_flags {
diff --git a/tools/aconfig/src/aconfig.rs b/tools/aconfig/src/aconfig.rs
index b9fa324..5e7c861 100644
--- a/tools/aconfig/src/aconfig.rs
+++ b/tools/aconfig/src/aconfig.rs
@@ -81,6 +81,7 @@
 #[derive(Debug, PartialEq, Eq)]
 pub struct FlagDeclaration {
     pub name: String,
+    pub namespace: String,
     pub description: String,
 }
 
@@ -100,16 +101,19 @@
         let Some(name) = proto.name else {
             bail!("missing 'name' field");
         };
+        let Some(namespace) = proto.namespace else {
+            bail!("missing 'namespace' field");
+        };
         let Some(description) = proto.description else {
             bail!("missing 'description' field");
         };
-        Ok(FlagDeclaration { name, description })
+        Ok(FlagDeclaration { name, namespace, description })
     }
 }
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct FlagDeclarations {
-    pub namespace: String,
+    pub package: String,
     pub flags: Vec<FlagDeclaration>,
 }
 
@@ -117,20 +121,20 @@
     pub fn try_from_text_proto(text_proto: &str) -> Result<FlagDeclarations> {
         let proto: ProtoFlagDeclarations = crate::protos::try_from_text_proto(text_proto)
             .with_context(|| text_proto.to_owned())?;
-        let Some(namespace) = proto.namespace else {
-            bail!("missing 'namespace' field");
+        let Some(package) = proto.package else {
+            bail!("missing 'package' field");
         };
         let mut flags = vec![];
         for proto_flag in proto.flag.into_iter() {
             flags.push(proto_flag.try_into()?);
         }
-        Ok(FlagDeclarations { namespace, flags })
+        Ok(FlagDeclarations { package, flags })
     }
 }
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct FlagValue {
-    pub namespace: String,
+    pub package: String,
     pub name: String,
     pub state: FlagState,
     pub permission: Permission,
@@ -153,8 +157,8 @@
     type Error = Error;
 
     fn try_from(proto: ProtoFlagValue) -> Result<Self, Self::Error> {
-        let Some(namespace) = proto.namespace else {
-            bail!("missing 'namespace' field");
+        let Some(package) = proto.package else {
+            bail!("missing 'package' field");
         };
         let Some(name) = proto.name else {
             bail!("missing 'name' field");
@@ -167,7 +171,7 @@
             bail!("missing 'permission' field");
         };
         let permission = proto_permission.try_into()?;
-        Ok(FlagValue { namespace, name, state, permission })
+        Ok(FlagValue { package, name, state, permission })
     }
 }
 
@@ -184,8 +188,9 @@
 impl From<Item> for ProtoParsedFlag {
     fn from(item: Item) -> Self {
         let mut proto = crate::protos::ProtoParsedFlag::new();
-        proto.set_namespace(item.namespace.to_owned());
+        proto.set_package(item.package.to_owned());
         proto.set_name(item.name.clone());
+        proto.set_namespace(item.namespace.clone());
         proto.set_description(item.description.clone());
         proto.set_state(item.state.into());
         proto.set_permission(item.permission.into());
@@ -214,11 +219,13 @@
     fn test_flag_try_from_text_proto() {
         let expected = FlagDeclaration {
             name: "1234".to_owned(),
+            namespace: "ns".to_owned(),
             description: "Description of the flag".to_owned(),
         };
 
         let s = r#"
         name: "1234"
+        namespace: "ns"
         description: "Description of the flag"
         "#;
         let actual = FlagDeclaration::try_from_text_proto(s).unwrap();
@@ -242,23 +249,33 @@
     }
 
     #[test]
-    fn test_namespace_try_from_text_proto() {
+    fn test_package_try_from_text_proto() {
         let expected = FlagDeclarations {
-            namespace: "ns".to_owned(),
+            package: "com.example".to_owned(),
             flags: vec![
-                FlagDeclaration { name: "a".to_owned(), description: "A".to_owned() },
-                FlagDeclaration { name: "b".to_owned(), description: "B".to_owned() },
+                FlagDeclaration {
+                    name: "a".to_owned(),
+                    namespace: "ns".to_owned(),
+                    description: "A".to_owned(),
+                },
+                FlagDeclaration {
+                    name: "b".to_owned(),
+                    namespace: "ns".to_owned(),
+                    description: "B".to_owned(),
+                },
             ],
         };
 
         let s = r#"
-        namespace: "ns"
+        package: "com.example"
         flag {
             name: "a"
+            namespace: "ns"
             description: "A"
         }
         flag {
             name: "b"
+            namespace: "ns"
             description: "B"
         }
         "#;
@@ -270,14 +287,14 @@
     #[test]
     fn test_flag_declaration_try_from_text_proto_list() {
         let expected = FlagValue {
-            namespace: "ns".to_owned(),
+            package: "com.example".to_owned(),
             name: "1234".to_owned(),
             state: FlagState::Enabled,
             permission: Permission::ReadOnly,
         };
 
         let s = r#"
-        namespace: "ns"
+        package: "com.example"
         name: "1234"
         state: ENABLED
         permission: READ_ONLY
diff --git a/tools/aconfig/src/cache.rs b/tools/aconfig/src/cache.rs
index 44ad3dd..dd54480 100644
--- a/tools/aconfig/src/cache.rs
+++ b/tools/aconfig/src/cache.rs
@@ -34,12 +34,13 @@
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Item {
-    // TODO: duplicating the Cache.namespace as Item.namespace makes the internal representation
+    // TODO: duplicating the Cache.package as Item.package makes the internal representation
     // closer to the proto message `parsed_flag`; hopefully this will enable us to replace the Item
-    // struct and use a newtype instead once aconfig has matured. Until then, namespace should
+    // struct and use a newtype instead once aconfig has matured. Until then, package should
     // really be a Cow<String>.
-    pub namespace: String,
+    pub package: String,
     pub name: String,
+    pub namespace: String,
     pub description: String,
     pub state: FlagState,
     pub permission: Permission,
@@ -48,7 +49,7 @@
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Cache {
-    namespace: String,
+    package: String,
     items: Vec<Item>,
 }
 
@@ -96,9 +97,9 @@
         self.items.into_iter()
     }
 
-    pub fn namespace(&self) -> &str {
-        debug_assert!(!self.namespace.is_empty());
-        &self.namespace
+    pub fn package(&self) -> &str {
+        debug_assert!(!self.package.is_empty());
+        &self.package
     }
 }
 
@@ -108,9 +109,9 @@
 }
 
 impl CacheBuilder {
-    pub fn new(namespace: String) -> Result<CacheBuilder> {
-        ensure!(codegen::is_valid_identifier(&namespace), "bad namespace");
-        let cache = Cache { namespace, items: vec![] };
+    pub fn new(package: String) -> Result<CacheBuilder> {
+        ensure!(codegen::is_valid_package_ident(&package), "bad package");
+        let cache = Cache { package, items: vec![] };
         Ok(CacheBuilder { cache })
     }
 
@@ -119,7 +120,8 @@
         source: Source,
         declaration: FlagDeclaration,
     ) -> Result<&mut CacheBuilder> {
-        ensure!(codegen::is_valid_identifier(&declaration.name), "bad flag name");
+        ensure!(codegen::is_valid_name_ident(&declaration.name), "bad flag name");
+        ensure!(codegen::is_valid_name_ident(&declaration.namespace), "bad namespace");
         ensure!(!declaration.description.is_empty(), "empty flag description");
         ensure!(
             self.cache.items.iter().all(|item| item.name != declaration.name),
@@ -128,8 +130,9 @@
             source
         );
         self.cache.items.push(Item {
-            namespace: self.cache.namespace.clone(),
+            package: self.cache.package.clone(),
             name: declaration.name.clone(),
+            namespace: declaration.namespace.clone(),
             description: declaration.description,
             state: DEFAULT_FLAG_STATE,
             permission: DEFAULT_FLAG_PERMISSION,
@@ -147,18 +150,18 @@
         source: Source,
         value: FlagValue,
     ) -> Result<&mut CacheBuilder> {
-        ensure!(codegen::is_valid_identifier(&value.namespace), "bad flag namespace");
-        ensure!(codegen::is_valid_identifier(&value.name), "bad flag name");
+        ensure!(codegen::is_valid_package_ident(&value.package), "bad flag package");
+        ensure!(codegen::is_valid_name_ident(&value.name), "bad flag name");
         ensure!(
-            value.namespace == self.cache.namespace,
-            "failed to set values for flag {}/{} from {}: expected namespace {}",
-            value.namespace,
+            value.package == self.cache.package,
+            "failed to set values for flag {}/{} from {}: expected package {}",
+            value.package,
             value.name,
             source,
-            self.cache.namespace
+            self.cache.package
         );
         let Some(existing_item) = self.cache.items.iter_mut().find(|item| item.name == value.name) else {
-            bail!("failed to set values for flag {}/{} from {}: flag not declared", value.namespace, value.name, source);
+            bail!("failed to set values for flag {}/{} from {}: flag not declared", value.package, value.name, source);
         };
         existing_item.state = value.state;
         existing_item.permission = value.permission;
@@ -179,21 +182,28 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::aconfig::{FlagState, Permission};
 
     #[test]
     fn test_add_flag_declaration() {
-        let mut builder = CacheBuilder::new("ns".to_string()).unwrap();
+        let mut builder = CacheBuilder::new("com.example".to_string()).unwrap();
         builder
             .add_flag_declaration(
                 Source::File("first.txt".to_string()),
-                FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
+                FlagDeclaration {
+                    name: "foo".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "desc".to_string(),
+                },
             )
             .unwrap();
         let error = builder
             .add_flag_declaration(
                 Source::File("second.txt".to_string()),
-                FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
+                FlagDeclaration {
+                    name: "foo".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "desc".to_string(),
+                },
             )
             .unwrap_err();
         assert_eq!(
@@ -203,7 +213,11 @@
         builder
             .add_flag_declaration(
                 Source::File("first.txt".to_string()),
-                FlagDeclaration { name: "bar".to_string(), description: "desc".to_string() },
+                FlagDeclaration {
+                    name: "bar".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "desc".to_string(),
+                },
             )
             .unwrap();
 
@@ -218,12 +232,12 @@
 
     #[test]
     fn test_add_flag_value() {
-        let mut builder = CacheBuilder::new("ns".to_string()).unwrap();
+        let mut builder = CacheBuilder::new("com.example".to_string()).unwrap();
         let error = builder
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "ns".to_string(),
+                    package: "com.example".to_string(),
                     name: "foo".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadOnly,
@@ -232,13 +246,17 @@
             .unwrap_err();
         assert_eq!(
             &format!("{:?}", error),
-            "failed to set values for flag ns/foo from <memory>: flag not declared"
+            "failed to set values for flag com.example/foo from <memory>: flag not declared"
         );
 
         builder
             .add_flag_declaration(
                 Source::File("first.txt".to_string()),
-                FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
+                FlagDeclaration {
+                    name: "foo".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "desc".to_string(),
+                },
             )
             .unwrap();
 
@@ -246,7 +264,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "ns".to_string(),
+                    package: "com.example".to_string(),
                     name: "foo".to_string(),
                     state: FlagState::Disabled,
                     permission: Permission::ReadOnly,
@@ -258,7 +276,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "ns".to_string(),
+                    package: "com.example".to_string(),
                     name: "foo".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadWrite,
@@ -266,19 +284,19 @@
             )
             .unwrap();
 
-        // different namespace -> no-op
+        // different package -> no-op
         let error = builder
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "some_other_namespace".to_string(),
+                    package: "some_other_package".to_string(),
                     name: "foo".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadOnly,
                 },
             )
             .unwrap_err();
-        assert_eq!(&format!("{:?}", error), "failed to set values for flag some_other_namespace/foo from <memory>: expected namespace ns");
+        assert_eq!(&format!("{:?}", error), "failed to set values for flag some_other_package/foo from <memory>: expected package com.example");
 
         let cache = builder.build();
         let item = cache.iter().find(|&item| item.name == "foo").unwrap();
@@ -287,18 +305,22 @@
     }
 
     #[test]
-    fn test_reject_empty_cache_namespace() {
+    fn test_reject_empty_cache_package() {
         CacheBuilder::new("".to_string()).unwrap_err();
     }
 
     #[test]
     fn test_reject_empty_flag_declaration_fields() {
-        let mut builder = CacheBuilder::new("ns".to_string()).unwrap();
+        let mut builder = CacheBuilder::new("com.example".to_string()).unwrap();
 
         let error = builder
             .add_flag_declaration(
                 Source::Memory,
-                FlagDeclaration { name: "".to_string(), description: "Description".to_string() },
+                FlagDeclaration {
+                    name: "".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "Description".to_string(),
+                },
             )
             .unwrap_err();
         assert_eq!(&format!("{:?}", error), "bad flag name");
@@ -306,7 +328,11 @@
         let error = builder
             .add_flag_declaration(
                 Source::Memory,
-                FlagDeclaration { name: "foo".to_string(), description: "".to_string() },
+                FlagDeclaration {
+                    name: "foo".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "".to_string(),
+                },
             )
             .unwrap_err();
         assert_eq!(&format!("{:?}", error), "empty flag description");
@@ -314,11 +340,15 @@
 
     #[test]
     fn test_reject_empty_flag_value_files() {
-        let mut builder = CacheBuilder::new("ns".to_string()).unwrap();
+        let mut builder = CacheBuilder::new("com.example".to_string()).unwrap();
         builder
             .add_flag_declaration(
                 Source::Memory,
-                FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
+                FlagDeclaration {
+                    name: "foo".to_string(),
+                    namespace: "ns".to_string(),
+                    description: "desc".to_string(),
+                },
             )
             .unwrap();
 
@@ -326,20 +356,20 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "".to_string(),
+                    package: "".to_string(),
                     name: "foo".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadOnly,
                 },
             )
             .unwrap_err();
-        assert_eq!(&format!("{:?}", error), "bad flag namespace");
+        assert_eq!(&format!("{:?}", error), "bad flag package");
 
         let error = builder
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: "ns".to_string(),
+                    package: "com.example".to_string(),
                     name: "".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadOnly,
diff --git a/tools/aconfig/src/codegen.rs b/tools/aconfig/src/codegen.rs
index b60ec51..fea9961 100644
--- a/tools/aconfig/src/codegen.rs
+++ b/tools/aconfig/src/codegen.rs
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-pub fn is_valid_identifier(s: &str) -> bool {
+use anyhow::{ensure, Result};
+
+pub fn is_valid_name_ident(s: &str) -> bool {
     // Identifiers must match [a-z][a-z0-9_]*
     let mut chars = s.chars();
     let Some(first) = chars.next() else {
@@ -26,18 +28,54 @@
     chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_')
 }
 
+pub fn is_valid_package_ident(s: &str) -> bool {
+    s.split('.').all(is_valid_name_ident)
+}
+
+pub fn create_device_config_ident(package: &str, flag_name: &str) -> Result<String> {
+    ensure!(is_valid_package_ident(package), "bad package");
+    ensure!(is_valid_package_ident(flag_name), "bad flag name");
+    Ok(format!("{}.{}", package, flag_name))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
-    fn test_is_valid_identifier() {
-        assert!(is_valid_identifier("foo"));
-        assert!(is_valid_identifier("foo_bar_123"));
+    fn test_is_valid_name_ident() {
+        assert!(is_valid_name_ident("foo"));
+        assert!(is_valid_name_ident("foo_bar_123"));
 
-        assert!(!is_valid_identifier(""));
-        assert!(!is_valid_identifier("123_foo"));
-        assert!(!is_valid_identifier("foo-bar"));
-        assert!(!is_valid_identifier("foo-b\u{00e5}r"));
+        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"));
+    }
+
+    #[test]
+    fn test_is_valid_package_ident() {
+        assert!(is_valid_package_ident("foo"));
+        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(""));
+        assert!(!is_valid_package_ident("123_foo"));
+        assert!(!is_valid_package_ident("foo-bar"));
+        assert!(!is_valid_package_ident("foo-b\u{00e5}r"));
+        assert!(!is_valid_package_ident("foo.bar.123"));
+        assert!(!is_valid_package_ident(".foo.bar"));
+        assert!(!is_valid_package_ident("foo.bar."));
+        assert!(!is_valid_package_ident("."));
+        assert!(!is_valid_package_ident("foo..bar"));
+    }
+
+    #[test]
+    fn test_create_device_config_ident() {
+        assert_eq!(
+            "com.foo.bar.some_flag",
+            create_device_config_ident("com.foo.bar", "some_flag").unwrap()
+        );
     }
 }
diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs
index 2aeea6a..2c32bb0 100644
--- a/tools/aconfig/src/codegen_cpp.rs
+++ b/tools/aconfig/src/codegen_cpp.rs
@@ -14,29 +14,42 @@
  * limitations under the License.
  */
 
-use anyhow::Result;
+use anyhow::{ensure, Result};
 use serde::Serialize;
 use tinytemplate::TinyTemplate;
 
 use crate::aconfig::{FlagState, Permission};
 use crate::cache::{Cache, Item};
+use crate::codegen;
 use crate::commands::OutputFile;
 
 pub fn generate_cpp_code(cache: &Cache) -> Result<OutputFile> {
-    let class_elements: Vec<ClassElement> = cache.iter().map(create_class_element).collect();
+    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 namespace = cache.namespace().to_lowercase();
-    let context = Context { namespace: namespace.clone(), readwrite, class_elements };
+    let header = package.replace('.', "_");
+    let cpp_namespace = package.replace('.', "::");
+    ensure!(codegen::is_valid_name_ident(&header));
+    let context = Context {
+        header: header.clone(),
+        cpp_namespace,
+        package: package.to_string(),
+        readwrite,
+        class_elements,
+    };
     let mut template = TinyTemplate::new();
     template.add_template("cpp_code_gen", include_str!("../templates/cpp.template"))?;
     let contents = template.render("cpp_code_gen", &context)?;
-    let path = ["aconfig", &(namespace + ".h")].iter().collect();
+    let path = ["aconfig", &(header + ".h")].iter().collect();
     Ok(OutputFile { contents: contents.into(), path })
 }
 
 #[derive(Serialize)]
 struct Context {
-    pub namespace: String,
+    pub header: String,
+    pub cpp_namespace: String,
+    pub package: String,
     pub readwrite: bool,
     pub class_elements: Vec<ClassElement>,
 }
@@ -46,9 +59,11 @@
     pub readwrite: bool,
     pub default_value: String,
     pub flag_name: String,
+    pub device_config_namespace: String,
+    pub device_config_flag: String,
 }
 
-fn create_class_element(item: &Item) -> ClassElement {
+fn create_class_element(package: &str, item: &Item) -> ClassElement {
     ClassElement {
         readwrite: item.permission == Permission::ReadWrite,
         default_value: if item.state == FlagState::Enabled {
@@ -57,6 +72,9 @@
             "false".to_string()
         },
         flag_name: item.name.clone(),
+        device_config_namespace: item.namespace.to_string(),
+        device_config_flag: codegen::create_device_config_ident(package, &item.name)
+            .expect("values checked at cache creation time"),
     }
 }
 
@@ -69,13 +87,14 @@
 
     #[test]
     fn test_cpp_codegen_build_time_flag_only() {
-        let namespace = "my_namespace";
-        let mut builder = CacheBuilder::new(namespace.to_string()).unwrap();
+        let package = "com.example";
+        let mut builder = CacheBuilder::new(package.to_string()).unwrap();
         builder
             .add_flag_declaration(
                 Source::File("aconfig_one.txt".to_string()),
                 FlagDeclaration {
                     name: "my_flag_one".to_string(),
+                    namespace: "ns".to_string(),
                     description: "buildtime disable".to_string(),
                 },
             )
@@ -83,7 +102,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: namespace.to_string(),
+                    package: package.to_string(),
                     name: "my_flag_one".to_string(),
                     state: FlagState::Disabled,
                     permission: Permission::ReadOnly,
@@ -94,6 +113,7 @@
                 Source::File("aconfig_two.txt".to_string()),
                 FlagDeclaration {
                     name: "my_flag_two".to_string(),
+                    namespace: "ns".to_string(),
                     description: "buildtime enable".to_string(),
                 },
             )
@@ -101,7 +121,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: namespace.to_string(),
+                    package: package.to_string(),
                     name: "my_flag_two".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadOnly,
@@ -109,11 +129,10 @@
             )
             .unwrap();
         let cache = builder.build();
-        let expect_content = r#"#ifndef my_namespace_HEADER_H
-        #define my_namespace_HEADER_H
-        #include "my_namespace.h"
+        let expect_content = r#"#ifndef com_example_HEADER_H
+        #define com_example_HEADER_H
 
-        namespace my_namespace {
+        namespace com::example {
 
             class my_flag_one {
                 public:
@@ -133,7 +152,7 @@
         #endif
         "#;
         let file = generate_cpp_code(&cache).unwrap();
-        assert_eq!("aconfig/my_namespace.h", file.path.to_str().unwrap());
+        assert_eq!("aconfig/com_example.h", file.path.to_str().unwrap());
         assert_eq!(
             expect_content.replace(' ', ""),
             String::from_utf8(file.contents).unwrap().replace(' ', "")
@@ -142,13 +161,14 @@
 
     #[test]
     fn test_cpp_codegen_runtime_flag() {
-        let namespace = "my_namespace";
-        let mut builder = CacheBuilder::new(namespace.to_string()).unwrap();
+        let package = "com.example";
+        let mut builder = CacheBuilder::new(package.to_string()).unwrap();
         builder
             .add_flag_declaration(
                 Source::File("aconfig_one.txt".to_string()),
                 FlagDeclaration {
                     name: "my_flag_one".to_string(),
+                    namespace: "ns".to_string(),
                     description: "buildtime disable".to_string(),
                 },
             )
@@ -157,6 +177,7 @@
                 Source::File("aconfig_two.txt".to_string()),
                 FlagDeclaration {
                     name: "my_flag_two".to_string(),
+                    namespace: "ns".to_string(),
                     description: "runtime enable".to_string(),
                 },
             )
@@ -164,7 +185,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: namespace.to_string(),
+                    package: package.to_string(),
                     name: "my_flag_two".to_string(),
                     state: FlagState::Enabled,
                     permission: Permission::ReadWrite,
@@ -172,21 +193,20 @@
             )
             .unwrap();
         let cache = builder.build();
-        let expect_content = r#"#ifndef my_namespace_HEADER_H
-        #define my_namespace_HEADER_H
-        #include "my_namespace.h"
+        let expect_content = r#"#ifndef com_example_HEADER_H
+        #define com_example_HEADER_H
 
         #include <server_configurable_flags/get_flags.h>
         using namespace server_configurable_flags;
 
-        namespace my_namespace {
+        namespace com::example {
 
             class my_flag_one {
                 public:
                     virtual const bool value() {
                         return GetServerConfigurableFlag(
-                            "my_namespace",
-                            "my_flag_one",
+                            "ns",
+                            "com.example.my_flag_one",
                             "false") == "true";
                     }
             }
@@ -195,8 +215,8 @@
                 public:
                     virtual const bool value() {
                         return GetServerConfigurableFlag(
-                            "my_namespace",
-                            "my_flag_two",
+                            "ns",
+                            "com.example.my_flag_two",
                             "true") == "true";
                     }
             }
@@ -205,10 +225,13 @@
         #endif
         "#;
         let file = generate_cpp_code(&cache).unwrap();
-        assert_eq!("aconfig/my_namespace.h", file.path.to_str().unwrap());
+        assert_eq!("aconfig/com_example.h", file.path.to_str().unwrap());
         assert_eq!(
-            expect_content.replace(' ', ""),
-            String::from_utf8(file.contents).unwrap().replace(' ', "")
+            None,
+            crate::test::first_significant_code_diff(
+                expect_content,
+                &String::from_utf8(file.contents).unwrap()
+            )
         );
     }
 }
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 98288e7..dfd6766 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -21,17 +21,19 @@
 
 use crate::aconfig::{FlagState, Permission};
 use crate::cache::{Cache, Item};
+use crate::codegen;
 use crate::commands::OutputFile;
 
 pub fn generate_java_code(cache: &Cache) -> Result<OutputFile> {
-    let class_elements: Vec<ClassElement> = cache.iter().map(create_class_element).collect();
+    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 namespace = cache.namespace();
-    let context = Context { namespace: namespace.to_string(), readwrite, class_elements };
+    let context = Context { package: package.to_string(), readwrite, class_elements };
     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 = ["aconfig", namespace].iter().collect();
+    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 })
@@ -39,7 +41,7 @@
 
 #[derive(Serialize)]
 struct Context {
-    pub namespace: String,
+    pub package: String,
     pub readwrite: bool,
     pub class_elements: Vec<ClassElement>,
 }
@@ -49,11 +51,13 @@
     pub method_name: String,
     pub readwrite: bool,
     pub default_value: String,
-    pub feature_name: String,
-    pub flag_name: String,
+    pub device_config_namespace: String,
+    pub device_config_flag: String,
 }
 
-fn create_class_element(item: &Item) -> ClassElement {
+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.clone(),
         readwrite: item.permission == Permission::ReadWrite,
@@ -62,8 +66,8 @@
         } else {
             "false".to_string()
         },
-        feature_name: item.name.clone(),
-        flag_name: item.name.clone(),
+        device_config_namespace: item.namespace.clone(),
+        device_config_flag,
     }
 }
 
@@ -76,13 +80,14 @@
 
     #[test]
     fn test_generate_java_code() {
-        let namespace = "example";
-        let mut builder = CacheBuilder::new(namespace.to_string()).unwrap();
+        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(),
                 },
             )
@@ -91,6 +96,7 @@
                 Source::File("test2.txt".to_string()),
                 FlagDeclaration {
                     name: "test2".to_string(),
+                    namespace: "ns".to_string(),
                     description: "runtime disable".to_string(),
                 },
             )
@@ -98,7 +104,7 @@
             .add_flag_value(
                 Source::Memory,
                 FlagValue {
-                    namespace: namespace.to_string(),
+                    package: package.to_string(),
                     name: "test".to_string(),
                     state: FlagState::Disabled,
                     permission: Permission::ReadOnly,
@@ -106,7 +112,7 @@
             )
             .unwrap();
         let cache = builder.build();
-        let expect_content = r#"package aconfig.example;
+        let expect_content = r#"package com.example;
 
         import android.provider.DeviceConfig;
 
@@ -118,8 +124,8 @@
 
             public static boolean test2() {
                 return DeviceConfig.getBoolean(
-                    "example",
-                    "test2__test2",
+                    "ns",
+                    "com.example.test2",
                     false
                 );
             }
@@ -127,10 +133,13 @@
         }
         "#;
         let file = generate_java_code(&cache).unwrap();
-        assert_eq!("aconfig/example/Flags.java", file.path.to_str().unwrap());
+        assert_eq!("com/example/Flags.java", file.path.to_str().unwrap());
         assert_eq!(
-            expect_content.replace(' ', ""),
-            String::from_utf8(file.contents).unwrap().replace(' ', "")
+            None,
+            crate::test::first_significant_code_diff(
+                expect_content,
+                &String::from_utf8(file.contents).unwrap()
+            )
         );
     }
 }
diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs
index fe4231b..98caeae 100644
--- a/tools/aconfig/src/codegen_rust.rs
+++ b/tools/aconfig/src/codegen_rust.rs
@@ -20,13 +20,18 @@
 
 use crate::aconfig::{FlagState, Permission};
 use crate::cache::{Cache, Item};
+use crate::codegen;
 use crate::commands::OutputFile;
 
 pub fn generate_rust_code(cache: &Cache) -> Result<OutputFile> {
-    let namespace = cache.namespace();
+    let package = cache.package();
     let parsed_flags: Vec<TemplateParsedFlag> =
-        cache.iter().map(|item| create_template_parsed_flag(namespace, item)).collect();
-    let context = TemplateContext { namespace: namespace.to_string(), parsed_flags };
+        cache.iter().map(|item| TemplateParsedFlag::new(package, item)).collect();
+    let context = TemplateContext {
+        package: package.to_string(),
+        parsed_flags,
+        modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
+    };
     let mut template = TinyTemplate::new();
     template.add_template("rust_code_gen", include_str!("../templates/rust.template"))?;
     let contents = template.render("rust_code_gen", &context)?;
@@ -36,14 +41,16 @@
 
 #[derive(Serialize)]
 struct TemplateContext {
-    pub namespace: String,
+    pub package: String,
     pub parsed_flags: Vec<TemplateParsedFlag>,
+    pub modules: Vec<String>,
 }
 
 #[derive(Serialize)]
 struct TemplateParsedFlag {
     pub name: String,
-    pub fn_name: String,
+    pub device_config_namespace: String,
+    pub device_config_flag: String,
 
     // TinyTemplate's conditionals are limited to single <bool> expressions; list all options here
     // Invariant: exactly one of these fields will be true
@@ -52,78 +59,79 @@
     pub is_read_write: bool,
 }
 
-#[allow(clippy::nonminimal_bool)]
-fn create_template_parsed_flag(namespace: &str, item: &Item) -> TemplateParsedFlag {
-    let template = TemplateParsedFlag {
-        name: item.name.clone(),
-        fn_name: format!("{}_{}", namespace, &item.name),
-        is_read_only_enabled: item.permission == Permission::ReadOnly
-            && item.state == FlagState::Enabled,
-        is_read_only_disabled: item.permission == Permission::ReadOnly
-            && item.state == FlagState::Disabled,
-        is_read_write: item.permission == Permission::ReadWrite,
-    };
-    #[rustfmt::skip]
-    debug_assert!(
-        (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
-        (!template.is_read_only_enabled && template.is_read_only_disabled && !template.is_read_write) ||
-        (!template.is_read_only_enabled && !template.is_read_only_disabled && template.is_read_write),
-        "TemplateParsedFlag invariant failed: {} {} {}",
-        template.is_read_only_enabled,
-        template.is_read_only_disabled,
-        template.is_read_write,
-    );
-    template
+impl TemplateParsedFlag {
+    #[allow(clippy::nonminimal_bool)]
+    fn new(package: &str, item: &Item) -> Self {
+        let template = TemplateParsedFlag {
+            name: item.name.clone(),
+            device_config_namespace: item.namespace.to_string(),
+            device_config_flag: codegen::create_device_config_ident(package, &item.name)
+                .expect("values checked at cache creation time"),
+            is_read_only_enabled: item.permission == Permission::ReadOnly
+                && item.state == FlagState::Enabled,
+            is_read_only_disabled: item.permission == Permission::ReadOnly
+                && item.state == FlagState::Disabled,
+            is_read_write: item.permission == Permission::ReadWrite,
+        };
+        #[rustfmt::skip]
+        debug_assert!(
+            (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
+            (!template.is_read_only_enabled && template.is_read_only_disabled && !template.is_read_write) ||
+            (!template.is_read_only_enabled && !template.is_read_only_disabled && template.is_read_write),
+            "TemplateParsedFlag invariant failed: {} {} {}",
+            template.is_read_only_enabled,
+            template.is_read_only_disabled,
+            template.is_read_write,
+        );
+        template
+    }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::commands::{create_cache, Input, Source};
 
     #[test]
     fn test_generate_rust_code() {
-        let cache = create_cache(
-            "test",
-            vec![Input {
-                source: Source::File("testdata/test.aconfig".to_string()),
-                reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()),
-            }],
-            vec![
-                Input {
-                    source: Source::File("testdata/first.values".to_string()),
-                    reader: Box::new(include_bytes!("../testdata/first.values").as_slice()),
-                },
-                Input {
-                    source: Source::File("testdata/test.aconfig".to_string()),
-                    reader: Box::new(include_bytes!("../testdata/second.values").as_slice()),
-                },
-            ],
-        )
-        .unwrap();
+        let cache = crate::test::create_cache();
         let generated = generate_rust_code(&cache).unwrap();
         assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
         let expected = r#"
+pub mod com {
+pub mod android {
+pub mod aconfig {
+pub mod test {
 #[inline(always)]
-pub const fn r#test_disabled_ro() -> bool {
+pub const fn r#disabled_ro() -> bool {
     false
 }
 
 #[inline(always)]
-pub fn r#test_disabled_rw() -> bool {
-    flags_rust::GetServerConfigurableFlag("test", "disabled_rw", "false") == "true"
+pub fn r#disabled_rw() -> bool {
+    flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.disabled_rw", "false") == "true"
 }
 
 #[inline(always)]
-pub const fn r#test_enabled_ro() -> bool {
+pub const fn r#enabled_ro() -> bool {
     true
 }
 
 #[inline(always)]
-pub fn r#test_enabled_rw() -> bool {
-    flags_rust::GetServerConfigurableFlag("test", "enabled_rw", "false") == "true"
+pub fn r#enabled_rw() -> bool {
+    flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.enabled_rw", "false") == "true"
+}
+
+}
+}
+}
 }
 "#;
-        assert_eq!(expected.trim(), String::from_utf8(generated.contents).unwrap().trim());
+        assert_eq!(
+            None,
+            crate::test::first_significant_code_diff(
+                expected,
+                &String::from_utf8(generated.contents).unwrap()
+            )
+        );
     }
 }
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index cce1d7f..586ba04 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -22,8 +22,8 @@
 use std::io::Read;
 use std::path::PathBuf;
 
-use crate::aconfig::{FlagDeclarations, FlagValue};
-use crate::cache::{Cache, CacheBuilder};
+use crate::aconfig::{FlagDeclarations, FlagState, FlagValue, Permission};
+use crate::cache::{Cache, CacheBuilder, Item};
 use crate::codegen_cpp::generate_cpp_code;
 use crate::codegen_java::generate_java_code;
 use crate::codegen_rust::generate_rust_code;
@@ -55,12 +55,8 @@
     pub contents: Vec<u8>,
 }
 
-pub fn create_cache(
-    namespace: &str,
-    declarations: Vec<Input>,
-    values: Vec<Input>,
-) -> Result<Cache> {
-    let mut builder = CacheBuilder::new(namespace.to_owned())?;
+pub fn create_cache(package: &str, declarations: Vec<Input>, values: Vec<Input>) -> Result<Cache> {
+    let mut builder = CacheBuilder::new(package.to_owned())?;
 
     for mut input in declarations {
         let mut contents = String::new();
@@ -68,11 +64,11 @@
         let dec_list = FlagDeclarations::try_from_text_proto(&contents)
             .with_context(|| format!("Failed to parse {}", input.source))?;
         ensure!(
-            namespace == dec_list.namespace,
-            "Failed to parse {}: expected namespace {}, got {}",
+            package == dec_list.package,
+            "Failed to parse {}: expected package {}, got {}",
             input.source,
-            namespace,
-            dec_list.namespace
+            package,
+            dec_list.package
         );
         for d in dec_list.flags.into_iter() {
             builder.add_flag_declaration(input.source.clone(), d)?;
@@ -93,16 +89,53 @@
     Ok(builder.build())
 }
 
-pub fn create_java_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_java_code(cache)
+pub fn create_java_lib(cache: Cache) -> Result<OutputFile> {
+    generate_java_code(&cache)
 }
 
-pub fn create_cpp_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_cpp_code(cache)
+pub fn create_cpp_lib(cache: Cache) -> Result<OutputFile> {
+    generate_cpp_code(&cache)
 }
 
-pub fn create_rust_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_rust_code(cache)
+pub fn create_rust_lib(cache: Cache) -> Result<OutputFile> {
+    generate_rust_code(&cache)
+}
+
+pub fn create_device_config_defaults(caches: Vec<Cache>) -> Result<Vec<u8>> {
+    let mut output = Vec::new();
+    for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
+    {
+        let line = format!(
+            "{}:{}.{}={}\n",
+            item.namespace,
+            item.package,
+            item.name,
+            match item.state {
+                FlagState::Enabled => "enabled",
+                FlagState::Disabled => "disabled",
+            }
+        );
+        output.extend_from_slice(line.as_bytes());
+    }
+    Ok(output)
+}
+
+pub fn create_device_config_sysprops(caches: Vec<Cache>) -> Result<Vec<u8>> {
+    let mut output = Vec::new();
+    for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
+    {
+        let line = format!(
+            "persist.device_config.{}.{}={}\n",
+            item.package,
+            item.name,
+            match item.state {
+                FlagState::Enabled => "true",
+                FlagState::Disabled => "false",
+            }
+        );
+        output.extend_from_slice(line.as_bytes());
+    }
+    Ok(output)
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
@@ -112,29 +145,26 @@
     Protobuf,
 }
 
-pub fn dump_cache(mut caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
+pub fn dump_cache(caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
     let mut output = Vec::new();
-    caches.sort_by_cached_key(|cache| cache.namespace().to_string());
-    for cache in caches.into_iter() {
-        match format {
-            DumpFormat::Text => {
-                let mut lines = vec![];
-                for item in cache.iter() {
-                    lines.push(format!(
-                        "{}/{}: {:?} {:?}\n",
-                        item.namespace, item.name, item.state, item.permission
-                    ));
-                }
-                output.append(&mut lines.concat().into());
+    match format {
+        DumpFormat::Text => {
+            for item in sort_and_iter_items(caches) {
+                let line = format!(
+                    "{}/{}: {:?} {:?}\n",
+                    item.package, item.name, item.state, item.permission
+                );
+                output.extend_from_slice(line.as_bytes());
             }
-            DumpFormat::Debug => {
-                let mut lines = vec![];
-                for item in cache.iter() {
-                    lines.push(format!("{:#?}\n", item));
-                }
-                output.append(&mut lines.concat().into());
+        }
+        DumpFormat::Debug => {
+            for item in sort_and_iter_items(caches) {
+                let line = format!("{:#?}\n", item);
+                output.extend_from_slice(line.as_bytes());
             }
-            DumpFormat::Protobuf => {
+        }
+        DumpFormat::Protobuf => {
+            for cache in sort_and_iter_caches(caches) {
                 let parsed_flags: ProtoParsedFlags = cache.into();
                 parsed_flags.write_to_vec(&mut output)?;
             }
@@ -143,68 +173,96 @@
     Ok(output)
 }
 
+fn sort_and_iter_items(caches: Vec<Cache>) -> impl Iterator<Item = Item> {
+    sort_and_iter_caches(caches).flat_map(|cache| cache.into_iter())
+}
+
+fn sort_and_iter_caches(mut caches: Vec<Cache>) -> impl Iterator<Item = Cache> {
+    caches.sort_by_cached_key(|cache| cache.package().to_string());
+    caches.into_iter()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
     use crate::aconfig::{FlagState, Permission};
 
-    fn create_test_cache_ns1() -> Cache {
+    fn create_test_cache_com_example() -> Cache {
         let s = r#"
-        namespace: "ns1"
+        package: "com.example"
         flag {
             name: "a"
+            namespace: "ns"
             description: "Description of a"
         }
         flag {
             name: "b"
+            namespace: "ns"
             description: "Description of b"
         }
         "#;
         let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
         let o = r#"
         flag_value {
-            namespace: "ns1"
+            package: "com.example"
             name: "a"
             state: DISABLED
             permission: READ_ONLY
         }
         "#;
         let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
-        create_cache("ns1", declarations, values).unwrap()
+        create_cache("com.example", declarations, values).unwrap()
     }
 
-    fn create_test_cache_ns2() -> Cache {
+    fn create_test_cache_com_other() -> Cache {
         let s = r#"
-        namespace: "ns2"
+        package: "com.other"
         flag {
             name: "c"
+            namespace: "ns"
             description: "Description of c"
         }
         "#;
         let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
         let o = r#"
         flag_value {
-            namespace: "ns2"
+            package: "com.other"
             name: "c"
             state: DISABLED
             permission: READ_ONLY
         }
         "#;
         let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
-        create_cache("ns2", declarations, values).unwrap()
+        create_cache("com.other", declarations, values).unwrap()
     }
 
     #[test]
     fn test_create_cache() {
-        let caches = create_test_cache_ns1(); // calls create_cache
+        let caches = create_test_cache_com_example(); // calls create_cache
         let item = caches.iter().find(|&item| item.name == "a").unwrap();
         assert_eq!(FlagState::Disabled, item.state);
         assert_eq!(Permission::ReadOnly, item.permission);
     }
 
     #[test]
+    fn test_create_device_config_defaults() {
+        let caches = vec![crate::test::create_cache()];
+        let bytes = create_device_config_defaults(caches).unwrap();
+        let text = std::str::from_utf8(&bytes).unwrap();
+        assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
+    }
+
+    #[test]
+    fn test_create_device_config_sysprops() {
+        let caches = vec![crate::test::create_cache()];
+        let bytes = create_device_config_sysprops(caches).unwrap();
+        let text = std::str::from_utf8(&bytes).unwrap();
+        assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
+    }
+
+    #[test]
     fn test_dump_text_format() {
-        let caches = vec![create_test_cache_ns1()];
+        let caches = vec![create_test_cache_com_example()];
         let bytes = dump_cache(caches, DumpFormat::Text).unwrap();
         let text = std::str::from_utf8(&bytes).unwrap();
         assert!(text.contains("a: Disabled"));
@@ -215,7 +273,7 @@
         use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
         use protobuf::Message;
 
-        let caches = vec![create_test_cache_ns1()];
+        let caches = vec![create_test_cache_com_example()];
         let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
         let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
 
@@ -226,7 +284,7 @@
 
         let item =
             actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
-        assert_eq!(item.namespace(), "ns1");
+        assert_eq!(item.package(), "com.example");
         assert_eq!(item.name(), "b");
         assert_eq!(item.description(), "Description of b");
         assert_eq!(item.state(), ProtoFlagState::DISABLED);
@@ -240,18 +298,22 @@
 
     #[test]
     fn test_dump_multiple_caches() {
-        let caches = vec![create_test_cache_ns1(), create_test_cache_ns2()];
+        let caches = vec![create_test_cache_com_example(), create_test_cache_com_other()];
         let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
         let dump = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
         assert_eq!(
             dump.parsed_flag
                 .iter()
-                .map(|parsed_flag| format!("{}/{}", parsed_flag.namespace(), parsed_flag.name()))
+                .map(|parsed_flag| format!("{}/{}", parsed_flag.package(), parsed_flag.name()))
                 .collect::<Vec<_>>(),
-            vec!["ns1/a".to_string(), "ns1/b".to_string(), "ns2/c".to_string()]
+            vec![
+                "com.example/a".to_string(),
+                "com.example/b".to_string(),
+                "com.other/c".to_string()
+            ]
         );
 
-        let caches = vec![create_test_cache_ns2(), create_test_cache_ns1()];
+        let caches = vec![create_test_cache_com_other(), create_test_cache_com_example()];
         let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
         let dump_reversed_input = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
         assert_eq!(dump, dump_reversed_input);
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index 1d2ec95..5a820d9 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -33,6 +33,9 @@
 mod commands;
 mod protos;
 
+#[cfg(test)]
+mod test;
+
 use crate::cache::Cache;
 use commands::{DumpFormat, Input, OutputFile, Source};
 
@@ -41,7 +44,7 @@
         .subcommand_required(true)
         .subcommand(
             Command::new("create-cache")
-                .arg(Arg::new("namespace").long("namespace").required(true))
+                .arg(Arg::new("package").long("package").required(true))
                 .arg(Arg::new("declarations").long("declarations").action(ArgAction::Append))
                 .arg(Arg::new("values").long("values").action(ArgAction::Append))
                 .arg(Arg::new("cache").long("cache").required(true)),
@@ -62,6 +65,16 @@
                 .arg(Arg::new("out").long("out").required(true)),
         )
         .subcommand(
+            Command::new("create-device-config-defaults")
+                .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
+                .arg(Arg::new("out").long("out").default_value("-")),
+        )
+        .subcommand(
+            Command::new("create-device-config-sysprops")
+                .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
+                .arg(Arg::new("out").long("out").default_value("-")),
+        )
+        .subcommand(
             Command::new("dump")
                 .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
                 .arg(
@@ -108,14 +121,23 @@
     Ok(())
 }
 
+fn write_output_to_file_or_stdout(path: &str, data: &[u8]) -> Result<()> {
+    if path == "-" {
+        io::stdout().write_all(data)?;
+    } else {
+        fs::File::create(path)?.write_all(data)?;
+    }
+    Ok(())
+}
+
 fn main() -> Result<()> {
     let matches = cli().get_matches();
     match matches.subcommand() {
         Some(("create-cache", sub_matches)) => {
-            let namespace = get_required_arg::<String>(sub_matches, "namespace")?;
+            let package = get_required_arg::<String>(sub_matches, "package")?;
             let declarations = open_zero_or_more_files(sub_matches, "declarations")?;
             let values = open_zero_or_more_files(sub_matches, "values")?;
-            let cache = commands::create_cache(namespace, declarations, values)?;
+            let cache = commands::create_cache(package, declarations, values)?;
             let path = get_required_arg::<String>(sub_matches, "cache")?;
             let file = fs::File::create(path)?;
             cache.write_to_writer(file)?;
@@ -125,7 +147,7 @@
             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)?;
+            let generated_file = commands::create_java_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
         Some(("create-cpp-lib", sub_matches)) => {
@@ -133,7 +155,7 @@
             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_cpp_lib(&cache)?;
+            let generated_file = commands::create_cpp_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
         Some(("create-rust-lib", sub_matches)) => {
@@ -141,9 +163,31 @@
             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_rust_lib(&cache)?;
+            let generated_file = commands::create_rust_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
+        Some(("create-device-config-defaults", sub_matches)) => {
+            let mut caches = Vec::new();
+            for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
+                let file = fs::File::open(path)?;
+                let cache = Cache::read_from_reader(file)?;
+                caches.push(cache);
+            }
+            let output = commands::create_device_config_defaults(caches)?;
+            let path = get_required_arg::<String>(sub_matches, "out")?;
+            write_output_to_file_or_stdout(path, &output)?;
+        }
+        Some(("create-device-config-sysprops", sub_matches)) => {
+            let mut caches = Vec::new();
+            for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
+                let file = fs::File::open(path)?;
+                let cache = Cache::read_from_reader(file)?;
+                caches.push(cache);
+            }
+            let output = commands::create_device_config_sysprops(caches)?;
+            let path = get_required_arg::<String>(sub_matches, "out")?;
+            write_output_to_file_or_stdout(path, &output)?;
+        }
         Some(("dump", sub_matches)) => {
             let mut caches = Vec::new();
             for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
@@ -154,12 +198,7 @@
             let format = get_required_arg::<DumpFormat>(sub_matches, "format")?;
             let output = commands::dump_cache(caches, *format)?;
             let path = get_required_arg::<String>(sub_matches, "out")?;
-            let mut file: Box<dyn Write> = if *path == "-" {
-                Box::new(io::stdout())
-            } else {
-                Box::new(fs::File::create(path)?)
-            };
-            file.write_all(&output)?;
+            write_output_to_file_or_stdout(path, &output)?;
         }
         _ => unreachable!(),
     }
diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs
new file mode 100644
index 0000000..cc19c6a
--- /dev/null
+++ b/tools/aconfig/src/test.rs
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#[cfg(test)]
+pub mod test_utils {
+    use crate::cache::Cache;
+    use crate::commands::{Input, Source};
+    use itertools;
+
+    pub fn create_cache() -> Cache {
+        crate::commands::create_cache(
+            "com.android.aconfig.test",
+            vec![Input {
+                source: Source::File("testdata/test.aconfig".to_string()),
+                reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()),
+            }],
+            vec![
+                Input {
+                    source: Source::File("testdata/first.values".to_string()),
+                    reader: Box::new(include_bytes!("../testdata/first.values").as_slice()),
+                },
+                Input {
+                    source: Source::File("testdata/test.aconfig".to_string()),
+                    reader: Box::new(include_bytes!("../testdata/second.values").as_slice()),
+                },
+            ],
+        )
+        .unwrap()
+    }
+
+    pub fn first_significant_code_diff(a: &str, b: &str) -> Option<String> {
+        let a = a.lines().map(|line| line.trim_start()).filter(|line| !line.is_empty());
+        let b = b.lines().map(|line| line.trim_start()).filter(|line| !line.is_empty());
+        match itertools::diff_with(a, b, |left, right| left == right) {
+            Some(itertools::Diff::FirstMismatch(_, mut left, mut right)) => {
+                Some(format!("'{}' vs '{}'", left.next().unwrap(), right.next().unwrap()))
+            }
+            Some(itertools::Diff::Shorter(_, mut left)) => {
+                Some(format!("LHS trailing data: '{}'", left.next().unwrap()))
+            }
+            Some(itertools::Diff::Longer(_, mut right)) => {
+                Some(format!("RHS trailing data: '{}'", right.next().unwrap()))
+            }
+            None => None,
+        }
+    }
+
+    #[test]
+    fn test_first_significant_code_diff() {
+        assert!(first_significant_code_diff("", "").is_none());
+        assert!(first_significant_code_diff("   a", "\n\na\n").is_none());
+        let a = r#"
+        public class A {
+            private static final String FOO = "FOO";
+            public static void main(String[] args) {
+                System.out.println("FOO=" + FOO);
+            }
+        }
+        "#;
+        let b = r#"
+        public class A {
+            private static final String FOO = "BAR";
+            public static void main(String[] args) {
+                System.out.println("foo=" + FOO);
+            }
+        }
+        "#;
+        assert_eq!(Some(r#"'private static final String FOO = "FOO";' vs 'private static final String FOO = "BAR";'"#.to_string()), first_significant_code_diff(a, b));
+        assert_eq!(
+            Some("LHS trailing data: 'b'".to_string()),
+            first_significant_code_diff("a\nb", "a")
+        );
+        assert_eq!(
+            Some("RHS trailing data: 'b'".to_string()),
+            first_significant_code_diff("a", "a\nb")
+        );
+    }
+}
+
+#[cfg(test)]
+pub use test_utils::*;
diff --git a/tools/aconfig/templates/cpp.template b/tools/aconfig/templates/cpp.template
index ae8b59f..93f9b80 100644
--- a/tools/aconfig/templates/cpp.template
+++ b/tools/aconfig/templates/cpp.template
@@ -1,19 +1,18 @@
-#ifndef {namespace}_HEADER_H
-#define {namespace}_HEADER_H
-#include "{namespace}.h"
+#ifndef {header}_HEADER_H
+#define {header}_HEADER_H
 {{ if readwrite }}
 #include <server_configurable_flags/get_flags.h>
 using namespace server_configurable_flags;
 {{ endif }}
-namespace {namespace} \{
+namespace {cpp_namespace} \{
     {{ for item in class_elements}}
     class {item.flag_name} \{
         public:
             virtual const bool value() \{
                 {{ if item.readwrite- }}
                 return GetServerConfigurableFlag(
-                    "{namespace}",
-                    "{item.flag_name}",
+                    "{item.device_config_namespace}",
+                    "{item.device_config_flag}",
                     "{item.default_value}") == "true";
                 {{ -else- }}
                 return {item.default_value};
diff --git a/tools/aconfig/templates/java.template b/tools/aconfig/templates/java.template
index 30c7ad7..a3d3319 100644
--- a/tools/aconfig/templates/java.template
+++ b/tools/aconfig/templates/java.template
@@ -1,4 +1,4 @@
-package aconfig.{namespace};
+package {package};
 {{ if readwrite }}
 import android.provider.DeviceConfig;
 {{ endif }}
@@ -7,8 +7,8 @@
     public static boolean {item.method_name}() \{
         {{ if item.readwrite- }}
         return DeviceConfig.getBoolean(
-            "{namespace}",
-            "{item.feature_name}__{item.flag_name}",
+            "{item.device_config_namespace}",
+            "{item.device_config_flag}",
             {item.default_value}
         );
         {{ -else- }}
diff --git a/tools/aconfig/templates/rust.template b/tools/aconfig/templates/rust.template
index d7f4e8d..d914943 100644
--- a/tools/aconfig/templates/rust.template
+++ b/tools/aconfig/templates/rust.template
@@ -1,23 +1,29 @@
+{{- for mod in modules -}}
+pub mod {mod} \{
+{{ endfor -}}
 {{- for parsed_flag in parsed_flags -}}
 {{- if parsed_flag.is_read_only_disabled -}}
 #[inline(always)]
-pub const fn r#{parsed_flag.fn_name}() -> bool \{
+pub const fn r#{parsed_flag.name}() -> bool \{
     false
 }
 
 {{ endif -}}
 {{- if parsed_flag.is_read_only_enabled -}}
 #[inline(always)]
-pub const fn r#{parsed_flag.fn_name}() -> bool \{
+pub const fn r#{parsed_flag.name}() -> bool \{
     true
 }
 
 {{ endif -}}
 {{- if parsed_flag.is_read_write -}}
 #[inline(always)]
-pub fn r#{parsed_flag.fn_name}() -> bool \{
-    flags_rust::GetServerConfigurableFlag("{namespace}", "{parsed_flag.name}", "false") == "true"
+pub fn r#{parsed_flag.name}() -> bool \{
+    flags_rust::GetServerConfigurableFlag("{parsed_flag.device_config_namespace}", "{parsed_flag.device_config_flag}", "false") == "true"
 }
 
 {{ endif -}}
 {{- endfor -}}
+{{- for mod in modules -}}
+}
+{{ endfor -}}
diff --git a/tools/aconfig/testdata/first.values b/tools/aconfig/testdata/first.values
index 3c49111..e524404 100644
--- a/tools/aconfig/testdata/first.values
+++ b/tools/aconfig/testdata/first.values
@@ -1,17 +1,17 @@
 flag_value {
-    namespace: "test"
+    package: "com.android.aconfig.test"
     name: "disabled_ro"
     state: DISABLED
     permission: READ_ONLY
 }
 flag_value {
-    namespace: "test"
+    package: "com.android.aconfig.test"
     name: "enabled_ro"
     state: DISABLED
     permission: READ_WRITE
 }
 flag_value {
-    namespace: "test"
+    package: "com.android.aconfig.test"
     name: "enabled_rw"
     state: ENABLED
     permission: READ_WRITE
diff --git a/tools/aconfig/testdata/second.values b/tools/aconfig/testdata/second.values
index 3fe11ab..aa09cf6 100644
--- a/tools/aconfig/testdata/second.values
+++ b/tools/aconfig/testdata/second.values
@@ -1,5 +1,5 @@
 flag_value {
-    namespace: "test"
+    package: "com.android.aconfig.test"
     name: "enabled_ro"
     state: ENABLED
     permission: READ_ONLY
diff --git a/tools/aconfig/testdata/test.aconfig b/tools/aconfig/testdata/test.aconfig
index 986a526..d09396a 100644
--- a/tools/aconfig/testdata/test.aconfig
+++ b/tools/aconfig/testdata/test.aconfig
@@ -1,10 +1,11 @@
-namespace: "test"
+package: "com.android.aconfig.test"
 
 # This flag's final value is calculated from:
 # - test.aconfig: DISABLED + READ_WRITE (default)
 # - first.values: DISABLED + READ_ONLY
 flag {
     name: "disabled_ro"
+    namespace: "aconfig_test"
     description: "This flag is DISABLED + READ_ONLY"
 }
 
@@ -12,6 +13,7 @@
 # - test.aconfig: DISABLED + READ_WRITE (default)
 flag {
     name: "disabled_rw"
+    namespace: "aconfig_test"
     description: "This flag is DISABLED + READ_WRITE"
 }
 
@@ -21,6 +23,7 @@
 # - second.values: ENABLED + READ_ONLY
 flag {
     name: "enabled_ro"
+    namespace: "aconfig_test"
     description: "This flag is ENABLED + READ_ONLY"
 }
 
@@ -29,5 +32,6 @@
 # - first.values: ENABLED + READ_WRITE
 flag {
     name: "enabled_rw"
+    namespace: "aconfig_test"
     description: "This flag is ENABLED + READ_WRITE"
 }
diff --git a/tools/compliance/cmd/sbom/sbom.go b/tools/compliance/cmd/sbom/sbom.go
index f61289e..a53741f 100644
--- a/tools/compliance/cmd/sbom/sbom.go
+++ b/tools/compliance/cmd/sbom/sbom.go
@@ -35,7 +35,7 @@
 	"github.com/google/blueprint/deptools"
 
 	"github.com/spdx/tools-golang/builder/builder2v2"
-	"github.com/spdx/tools-golang/json"
+	spdx_json "github.com/spdx/tools-golang/json"
 	"github.com/spdx/tools-golang/spdx/common"
 	spdx "github.com/spdx/tools-golang/spdx/v2_2"
 	"github.com/spdx/tools-golang/spdxlib"
@@ -274,7 +274,7 @@
 	tn *compliance.TargetNode) (*projectmetadata.ProjectMetadata, error) {
 	pms, err := pmix.MetadataForProjects(tn.Projects()...)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read projects for %q: %w\n", tn, err)
+		return nil, fmt.Errorf("Unable to read projects for %q: %w\n", tn.Name(), err)
 	}
 	if len(pms) == 0 {
 		return nil, nil
diff --git a/tools/compliance/cmd/sbom/sbom_test.go b/tools/compliance/cmd/sbom/sbom_test.go
index 8a62713..13ba66d 100644
--- a/tools/compliance/cmd/sbom/sbom_test.go
+++ b/tools/compliance/cmd/sbom/sbom_test.go
@@ -25,6 +25,7 @@
 	"time"
 
 	"android/soong/tools/compliance"
+
 	"github.com/spdx/tools-golang/builder/builder2v2"
 	"github.com/spdx/tools-golang/spdx/common"
 	spdx "github.com/spdx/tools-golang/spdx/v2_2"
@@ -2375,8 +2376,8 @@
 	if doc.DocumentName == "" {
 		return fmt.Errorf("DocumentName: got nothing, want Document Name")
 	}
-	if fmt.Sprintf("%v", doc.CreationInfo.Creators[1].Creator) != "Google LLC" {
-		return fmt.Errorf("Creator: got %v, want  'Google LLC'")
+	if c := fmt.Sprintf("%v", doc.CreationInfo.Creators[1].Creator); c != "Google LLC" {
+		return fmt.Errorf("Creator: got %v, want  'Google LLC'", c)
 	}
 	_, err := time.Parse(time.RFC3339, doc.CreationInfo.Created)
 	if err != nil {
diff --git a/tools/compliance/go.mod b/tools/compliance/go.mod
index 088915a..1928189 100644
--- a/tools/compliance/go.mod
+++ b/tools/compliance/go.mod
@@ -7,8 +7,11 @@
 require (
 	android/soong v0.0.0
 	github.com/google/blueprint v0.0.0
+	github.com/spdx/tools-golang v0.0.0
 )
 
+replace github.com/spdx/tools-golang v0.0.0 => ../../../../external/spdx-tools
+
 require golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
 
 replace android/soong v0.0.0 => ../../../soong
diff --git a/tools/find_static_candidates.py b/tools/find_static_candidates.py
new file mode 100644
index 0000000..7511b36
--- /dev/null
+++ b/tools/find_static_candidates.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python3
+
+"""Tool to find static libraries that maybe should be shared libraries and shared libraries that maybe should be static libraries.
+
+This tool only looks at the module-info.json for the current target.
+
+Example of "class" types for each of the modules in module-info.json
+  "EXECUTABLES": 2307,
+  "ETC": 9094,
+  "NATIVE_TESTS": 10461,
+  "APPS": 2885,
+  "JAVA_LIBRARIES": 5205,
+  "EXECUTABLES/JAVA_LIBRARIES": 119,
+  "FAKE": 553,
+  "SHARED_LIBRARIES/STATIC_LIBRARIES": 7591,
+  "STATIC_LIBRARIES": 11535,
+  "SHARED_LIBRARIES": 10852,
+  "HEADER_LIBRARIES": 1897,
+  "DYLIB_LIBRARIES": 1262,
+  "RLIB_LIBRARIES": 3413,
+  "ROBOLECTRIC": 39,
+  "PACKAGING": 5,
+  "PROC_MACRO_LIBRARIES": 36,
+  "RENDERSCRIPT_BITCODE": 17,
+  "DYLIB_LIBRARIES/RLIB_LIBRARIES": 8,
+  "ETC/FAKE": 1
+
+None of the "SHARED_LIBRARIES/STATIC_LIBRARIES" are double counted in the
+modules with one class
+RLIB/
+
+All of these classes have shared_libs and/or static_libs
+    "EXECUTABLES",
+    "SHARED_LIBRARIES",
+    "STATIC_LIBRARIES",
+    "SHARED_LIBRARIES/STATIC_LIBRARIES", # cc_library
+    "HEADER_LIBRARIES",
+    "NATIVE_TESTS", # test modules
+    "DYLIB_LIBRARIES", # rust
+    "RLIB_LIBRARIES", # rust
+    "ETC", # rust_bindgen
+"""
+
+from collections import defaultdict
+
+import json, os, argparse
+
+ANDROID_PRODUCT_OUT = os.environ.get("ANDROID_PRODUCT_OUT")
+# If a shared library is used less than MAX_SHARED_INCLUSIONS times in a target,
+# then it will likely save memory by changing it to a static library
+# This move will also use less storage
+MAX_SHARED_INCLUSIONS = 2
+# If a static library is used more than MAX_STATIC_INCLUSIONS times in a target,
+# then it will likely save memory by changing it to a shared library
+# This move will also likely use less storage
+MIN_STATIC_INCLUSIONS = 3
+
+
+def parse_args():
+  parser = argparse.ArgumentParser(
+      description=(
+          "Parse module-info.jso and display information about static and"
+          " shared library dependencies."
+      )
+  )
+  parser.add_argument(
+      "--module", dest="module", help="Print the info for the module."
+  )
+  parser.add_argument(
+      "--shared",
+      dest="print_shared",
+      action=argparse.BooleanOptionalAction,
+      help=(
+          "Print the list of libraries that are shared_libs for fewer than {}"
+          " modules.".format(MAX_SHARED_INCLUSIONS)
+      ),
+  )
+  parser.add_argument(
+      "--static",
+      dest="print_static",
+      action=argparse.BooleanOptionalAction,
+      help=(
+          "Print the list of libraries that are static_libs for more than {}"
+          " modules.".format(MIN_STATIC_INCLUSIONS)
+      ),
+  )
+  parser.add_argument(
+      "--recursive",
+      dest="recursive",
+      action=argparse.BooleanOptionalAction,
+      default=True,
+      help=(
+          "Gather all dependencies of EXECUTABLES recursvily before calculating"
+          " the stats. This eliminates duplicates from multiple libraries"
+          " including the same dependencies in a single binary."
+      ),
+  )
+  parser.add_argument(
+      "--both",
+      dest="both",
+      action=argparse.BooleanOptionalAction,
+      default=False,
+      help=(
+          "Print a list of libraries that are including libraries as both"
+          " static and shared"
+      ),
+  )
+  return parser.parse_args()
+
+
+class TransitiveHelper:
+
+  def __init__(self):
+    # keep a list of already expanded libraries so we don't end up in a cycle
+    self.visited = defaultdict(lambda: defaultdict(set))
+
+  # module is an object from the module-info dictionary
+  # module_info is the dictionary from module-info.json
+  # modify the module's shared_libs and static_libs with all of the transient
+  # dependencies required from all of the explicit dependencies
+  def flattenDeps(self, module, module_info):
+    libs_snapshot = dict(shared_libs = set(module["shared_libs"]), static_libs = set(module["static_libs"]))
+
+    for lib_class in ["shared_libs", "static_libs"]:
+      for lib in libs_snapshot[lib_class]:
+        if not lib or lib not in module_info:
+          continue
+        if lib in self.visited:
+          module[lib_class].update(self.visited[lib][lib_class])
+        else:
+          res = self.flattenDeps(module_info[lib], module_info)
+          module[lib_class].update(res[lib_class])
+          self.visited[lib][lib_class].update(res[lib_class])
+
+    return module
+
+def main():
+  module_info = json.load(open(ANDROID_PRODUCT_OUT + "/module-info.json"))
+  # turn all of the static_libs and shared_libs lists into sets to make them
+  # easier to update
+  for _, module in module_info.items():
+    module["shared_libs"] = set(module["shared_libs"])
+    module["static_libs"] = set(module["static_libs"])
+
+  args = parse_args()
+
+  if args.module:
+    if args.module not in module_info:
+      print("Module {} does not exist".format(args.module))
+      exit(1)
+
+  includedStatically = defaultdict(set)
+  includedSharedly = defaultdict(set)
+  includedBothly = defaultdict(set)
+  transitive = TransitiveHelper()
+  for name, module in module_info.items():
+    if args.recursive:
+      # in this recursive mode we only want to see what is included by the executables
+      if "EXECUTABLES" not in module["class"]:
+        continue
+      module = transitive.flattenDeps(module, module_info)
+      # filter out fuzzers by their dependency on clang
+      if "libclang_rt.fuzzer" in module["static_libs"]:
+        continue
+    else:
+      if "NATIVE_TESTS" in module["class"]:
+        # We don't care about how tests are including libraries
+        continue
+
+    # count all of the shared and static libs included in this module
+    for lib in module["shared_libs"]:
+      includedSharedly[lib].add(name)
+    for lib in module["static_libs"]:
+      includedStatically[lib].add(name)
+
+    intersection = set(module["shared_libs"]).intersection(
+        module["static_libs"]
+    )
+    if intersection:
+      includedBothly[name] = intersection
+
+  if args.print_shared:
+    print(
+        "Shared libraries that are included by fewer than {} modules on a"
+        " device:".format(MAX_SHARED_INCLUSIONS)
+    )
+    for name, libs in includedSharedly.items():
+      if len(libs) < MAX_SHARED_INCLUSIONS:
+        print("{}: {} included by: {}".format(name, len(libs), libs))
+
+  if args.print_static:
+    print(
+        "Libraries that are included statically by more than {} modules on a"
+        " device:".format(MIN_STATIC_INCLUSIONS)
+    )
+    for name, libs in includedStatically.items():
+      if len(libs) > MIN_STATIC_INCLUSIONS:
+        print("{}: {} included by: {}".format(name, len(libs), libs))
+
+  if args.both:
+    allIncludedBothly = set()
+    for name, libs in includedBothly.items():
+      allIncludedBothly.update(libs)
+
+    print(
+        "List of libraries used both statically and shared in the same"
+        " processes:\n {}\n\n".format("\n".join(sorted(allIncludedBothly)))
+    )
+    print(
+        "List of libraries used both statically and shared in any processes:\n {}".format("\n".join(sorted(includedStatically.keys() & includedSharedly.keys()))))
+
+  if args.module:
+    print(json.dumps(module_info[args.module], default=list, indent=2))
+    print(
+        "{} is included in shared_libs {} times by these modules: {}".format(
+            args.module, len(includedSharedly[args.module]),
+            includedSharedly[args.module]
+        )
+    )
+    print(
+        "{} is included in static_libs {} times by these modules: {}".format(
+            args.module, len(includedStatically[args.module]),
+            includedStatically[args.module]
+        )
+    )
+    print("Shared libs included by this module that are used in fewer than {} processes:\n{}".format(
+        MAX_SHARED_INCLUSIONS, [x for x in module_info[args.module]["shared_libs"] if len(includedSharedly[x]) < MAX_SHARED_INCLUSIONS]))
+
+
+
+if __name__ == "__main__":
+  main()
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index afbe81a..4c0d391 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -1063,6 +1063,8 @@
       # ZIP_STORED.
       common.ZipWriteStr(output_zip, care_map_name, care_map_data,
                          compress_type=zipfile.ZIP_STORED)
+      # break here to avoid going into else when care map has been handled
+      break
     else:
       logger.warning("Cannot find care map file in target_file package")