Merge "aconfig: read from new storage in Rust codegen" into main
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 33c3d37..591781e 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -20,26 +20,32 @@
 
 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
 
+use std::collections::HashMap;
+
 use crate::codegen;
 use crate::codegen::CodegenMode;
 use crate::commands::OutputFile;
 
 pub fn generate_rust_code<I>(
     package: &str,
+    flag_ids: HashMap<String, u16>,
     parsed_flags_iter: I,
     codegen_mode: CodegenMode,
+    allow_instrumentation: bool,
 ) -> Result<OutputFile>
 where
     I: Iterator<Item = ProtoParsedFlag>,
 {
-    let template_flags: Vec<TemplateParsedFlag> =
-        parsed_flags_iter.map(|pf| TemplateParsedFlag::new(package, &pf)).collect();
+    let template_flags: Vec<TemplateParsedFlag> = parsed_flags_iter
+        .map(|pf| TemplateParsedFlag::new(package, flag_ids.clone(), &pf))
+        .collect();
     let has_readwrite = template_flags.iter().any(|item| item.readwrite);
     let context = TemplateContext {
         package: package.to_string(),
         template_flags,
         modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
         has_readwrite,
+        allow_instrumentation,
     };
     let mut template = TinyTemplate::new();
     template.add_template(
@@ -62,6 +68,7 @@
     pub template_flags: Vec<TemplateParsedFlag>,
     pub modules: Vec<String>,
     pub has_readwrite: bool,
+    pub allow_instrumentation: bool,
 }
 
 #[derive(Serialize)]
@@ -69,25 +76,28 @@
     pub readwrite: bool,
     pub default_value: String,
     pub name: String,
+    pub container: String,
+    pub flag_offset: u16,
     pub device_config_namespace: String,
     pub device_config_flag: String,
 }
 
 impl TemplateParsedFlag {
     #[allow(clippy::nonminimal_bool)]
-    fn new(package: &str, pf: &ProtoParsedFlag) -> Self {
-        let template = TemplateParsedFlag {
+    fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
+        Self {
             readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
             default_value: match pf.state() {
                 ProtoFlagState::ENABLED => "true".to_string(),
                 ProtoFlagState::DISABLED => "false".to_string(),
             },
             name: pf.name().to_string(),
+            container: pf.container().to_string(),
+            flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
             device_config_namespace: pf.namespace().to_string(),
             device_config_flag: codegen::create_device_config_ident(package, pf.name())
                 .expect("values checked at flag parse time"),
-        };
-        template
+        }
     }
 }
 
@@ -97,6 +107,14 @@
 
     const PROD_EXPECTED: &str = r#"
 //! codegenerated rust flag lib
+use aconfig_storage_read_api::{StorageFileType, get_mapped_storage_file, get_boolean_flag_value, get_package_offset};
+use std::path::Path;
+use std::io::Write;
+use log::{info, error, LevelFilter};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+    "/metadata/aconfig/storage_test_mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigStorageTestMission1";
 
 /// flag provider
 pub struct FlagProvider;
@@ -492,6 +510,14 @@
 
     const EXPORTED_EXPECTED: &str = r#"
 //! codegenerated rust flag lib
+use aconfig_storage_read_api::{StorageFileType, get_mapped_storage_file, get_boolean_flag_value, get_package_offset};
+use std::path::Path;
+use std::io::Write;
+use log::{info, error, LevelFilter};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+    "/metadata/aconfig/storage_test_mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigStorageTestMission1";
 
 /// flag provider
 pub struct FlagProvider;
@@ -520,17 +546,20 @@
 impl FlagProvider {
     /// query flag disabled_rw_exported
     pub fn disabled_rw_exported(&self) -> bool {
-        *CACHED_disabled_rw_exported
+        let result = *CACHED_disabled_rw_exported;
+        result
     }
 
     /// query flag enabled_fixed_ro_exported
     pub fn enabled_fixed_ro_exported(&self) -> bool {
-        *CACHED_enabled_fixed_ro_exported
+        let result = *CACHED_enabled_fixed_ro_exported;
+        result
     }
 
     /// query flag enabled_ro_exported
     pub fn enabled_ro_exported(&self) -> bool {
-        *CACHED_enabled_ro_exported
+        let result = *CACHED_enabled_ro_exported;
+        result
     }
 }
 
@@ -558,6 +587,14 @@
 
     const FORCE_READ_ONLY_EXPECTED: &str = r#"
 //! codegenerated rust flag lib
+use aconfig_storage_read_api::{StorageFileType, get_mapped_storage_file, get_boolean_flag_value, get_package_offset};
+use std::path::Path;
+use std::io::Write;
+use log::{info, error, LevelFilter};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+    "/metadata/aconfig/storage_test_mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigStorageTestMission1";
 
 /// flag provider
 pub struct FlagProvider;
@@ -565,32 +602,344 @@
 impl FlagProvider {
     /// query flag disabled_ro
     pub fn disabled_ro(&self) -> bool {
-        false
+        let result = false;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'disabled_ro', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'disabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 0 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_ro': {}", err);
+                    return result;
+                }
+            };
+            if false != value {
+                let default_value = false;
+                error!("flag mismatch for 'disabled_ro'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 
     /// query flag disabled_rw
     pub fn disabled_rw(&self) -> bool {
-        false
+        let result = false;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'disabled_rw', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 1 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw': {}", err);
+                    return result;
+                }
+            };
+            if false != value {
+                let default_value = false;
+                error!("flag mismatch for 'disabled_rw'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 
     /// query flag disabled_rw_in_other_namespace
     pub fn disabled_rw_in_other_namespace(&self) -> bool {
-        false
+        let result = false;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw_in_other_namespace': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'disabled_rw_in_other_namespace', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw_in_other_namespace': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw_in_other_namespace': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 2 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'disabled_rw_in_other_namespace': {}", err);
+                    return result;
+                }
+            };
+            if false != value {
+                let default_value = false;
+                error!("flag mismatch for 'disabled_rw_in_other_namespace'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 
     /// query flag enabled_fixed_ro
     pub fn enabled_fixed_ro(&self) -> bool {
-        true
+        let result = true;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_fixed_ro': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'enabled_fixed_ro', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'enabled_fixed_ro': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_fixed_ro': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 3 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_fixed_ro': {}", err);
+                    return result;
+                }
+            };
+            if true != value {
+                let default_value = true;
+                error!("flag mismatch for 'enabled_fixed_ro'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 
     /// query flag enabled_ro
     pub fn enabled_ro(&self) -> bool {
-        true
+        let result = true;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'enabled_ro', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'enabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_ro': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 4 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_ro': {}", err);
+                    return result;
+                }
+            };
+            if true != value {
+                let default_value = true;
+                error!("flag mismatch for 'enabled_ro'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 
     /// query flag enabled_rw
     pub fn enabled_rw(&self) -> bool {
-        true
+        let result = true;
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe {
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+                Ok(file) => file,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "com.android.aconfig.test") {
+                Ok(Some(offset)) => offset,
+                Ok(None) => {
+                    error!("failed to read flag 'enabled_rw', not found in package map");
+                    return result;
+                },
+                Err(err) => {
+                    error!("failed to read flag 'enabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+                Ok(val_map) => val_map,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_rw': {}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, 5 + package_offset.boolean_offset) {
+                Ok(val) => val,
+                Err(err) => {
+                    error!("failed to read flag 'enabled_rw': {}", err);
+                    return result;
+                }
+            };
+            if true != value {
+                let default_value = true;
+                error!("flag mismatch for 'enabled_rw'. Legacy storage was {default_value}, new storage was {value}")
+            }
+        }
+        result
     }
 }
 
@@ -633,14 +982,22 @@
     true
 }
 "#;
+    use crate::commands::assign_flag_ids;
 
-    fn test_generate_rust_code(mode: CodegenMode) {
+    fn test_generate_rust_code(mode: CodegenMode, instrumentation: bool) {
         let parsed_flags = crate::test::parse_test_flags();
         let modified_parsed_flags =
             crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
-        let generated =
-            generate_rust_code(crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode)
-                .unwrap();
+        let flag_ids =
+            assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
+        let generated = generate_rust_code(
+            crate::test::TEST_PACKAGE,
+            flag_ids,
+            modified_parsed_flags.into_iter(),
+            mode,
+            instrumentation,
+        )
+        .unwrap();
         assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
         assert_eq!(
             None,
@@ -658,21 +1015,21 @@
 
     #[test]
     fn test_generate_rust_code_for_prod() {
-        test_generate_rust_code(CodegenMode::Production);
+        test_generate_rust_code(CodegenMode::Production, false);
     }
 
     #[test]
     fn test_generate_rust_code_for_test() {
-        test_generate_rust_code(CodegenMode::Test);
+        test_generate_rust_code(CodegenMode::Test, true);
     }
 
     #[test]
     fn test_generate_rust_code_for_exported() {
-        test_generate_rust_code(CodegenMode::Exported);
+        test_generate_rust_code(CodegenMode::Exported, true);
     }
 
     #[test]
     fn test_generate_rust_code_for_force_read_only() {
-        test_generate_rust_code(CodegenMode::ForceReadOnly);
+        test_generate_rust_code(CodegenMode::ForceReadOnly, true);
     }
 }
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 7736ce7..66bcb82 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -218,7 +218,11 @@
     generate_cpp_code(&package, modified_parsed_flags.into_iter(), codegen_mode)
 }
 
-pub fn create_rust_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<OutputFile> {
+pub fn create_rust_lib(
+    mut input: Input,
+    codegen_mode: CodegenMode,
+    allow_instrumentation: bool,
+) -> Result<OutputFile> {
     // // TODO(327420679): Enable export mode for native flag library
     ensure!(
         codegen_mode != CodegenMode::Exported,
@@ -230,8 +234,14 @@
         bail!("no parsed flags, or the parsed flags use different packages");
     };
     let package = package.to_string();
-    let _flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
-    generate_rust_code(&package, modified_parsed_flags.into_iter(), codegen_mode)
+    let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
+    generate_rust_code(
+        &package,
+        flag_ids,
+        modified_parsed_flags.into_iter(),
+        codegen_mode,
+        allow_instrumentation,
+    )
 }
 
 pub fn create_storage(
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index 69f5458..6dae8ac 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -90,6 +90,12 @@
                 .arg(Arg::new("cache").long("cache").required(true))
                 .arg(Arg::new("out").long("out").required(true))
                 .arg(
+                    Arg::new("allow-instrumentation")
+                        .long("allow-instrumentation")
+                        .value_parser(clap::value_parser!(bool))
+                        .default_value("false"),
+                )
+                .arg(
                     Arg::new("mode")
                         .long("mode")
                         .value_parser(EnumValueParser::<CodegenMode>::new())
@@ -251,8 +257,10 @@
         Some(("create-rust-lib", sub_matches)) => {
             let cache = open_single_file(sub_matches, "cache")?;
             let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
-            let generated_file =
-                commands::create_rust_lib(cache, *mode).context("failed to create rust lib")?;
+            let allow_instrumentation =
+                get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
+            let generated_file = commands::create_rust_lib(cache, *mode, *allow_instrumentation)
+                .context("failed to create rust lib")?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index f9a2829..4b1ad83 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -1,5 +1,14 @@
 //! codegenerated rust flag lib
 
+use aconfig_storage_read_api::\{StorageFileType, get_mapped_storage_file, get_boolean_flag_value, get_package_offset};
+use std::path::Path;
+use std::io::Write;
+use log::\{info, error, LevelFilter};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+    "/metadata/aconfig/storage_test_mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigStorageTestMission1";
+
 /// flag provider
 pub struct FlagProvider;
 
@@ -22,11 +31,76 @@
 {{ for flag in template_flags }}
     /// query flag {flag.name}
     pub fn {flag.name}(&self) -> bool \{
-    {{ -if flag.readwrite }}
+        {{ if not allow_instrumentation }}
+
+        {{ -if flag.readwrite }}
         *CACHED_{flag.name}
-    {{ -else }}
+        {{ -else }}
         {flag.default_value}
-    {{ -endif }}
+        {{ -endif }}
+
+        {{ else }}
+        let result = {{ -if flag.readwrite }} *CACHED_{flag.name}{{ else }} {flag.default_value} {{ -endif }};
+
+        {{ if flag.readwrite }}
+        result
+        {{ else }}
+
+        if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() \{
+            return result;
+        }
+
+        // This will be called multiple times. Subsequent calls after the first
+        // are noops.
+        logger::init(
+            logger::Config::default()
+                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_max_level(LevelFilter::Info),
+        );
+
+        unsafe \{
+            let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) \{
+                Ok(file) => file,
+                Err(err) => \{
+                    error!("failed to read flag '{flag.name}': \{}", err);
+                    return result;
+                }
+            };
+            let package_offset = match get_package_offset(&package_map, "{package}") \{
+                Ok(Some(offset)) => offset,
+                Ok(None) => \{
+                    error!("failed to read flag '{flag.name}', not found in package map");
+                    return result;
+                },
+                Err(err) => \{
+                    error!("failed to read flag '{flag.name}': \{}", err);
+                    return result;
+                }
+            };
+            let flag_val_map = match get_mapped_storage_file("{flag.container}", StorageFileType::FlagVal) \{
+                Ok(val_map) => val_map,
+                Err(err) => \{
+                    error!("failed to read flag '{flag.name}': \{}", err);
+                    return result;
+                }
+            };
+            let value = match get_boolean_flag_value(&flag_val_map, {flag.flag_offset} + package_offset.boolean_offset) \{
+                Ok(val) => val,
+                Err(err) => \{
+                    error!("failed to read flag '{flag.name}': \{}", err);
+                    return result;
+                }
+            };
+
+            if {flag.default_value} != value \{
+                let default_value = {flag.default_value};
+                error!("flag mismatch for '{flag.name}'. Legacy storage was \{default_value}, new storage was \{value}")
+            }
+        }
+
+        result
+        {{ endif }}
+        {{ endif }}
     }
 {{ endfor }}