aconfig: add ForceReadOnly mode to aconfig c/c++ codegen

This commit adds ForceReadOnly mode to c/c++ codegen.

Bug: 316357759
Test: atest aconfig.test aconfig.test.cpp aconfig.test.cpp.test_mode
aconfig.test.cpp.exported_mode aconfig.test.cpp.force_read_only_mode

Change-Id: I4842dd69993fe4fc1f504358f59513cf064919d9
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 37be2dd..5661681 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -179,6 +179,12 @@
     mode: "exported",
 }
 
+cc_aconfig_library {
+    name: "aconfig_test_cpp_library_force_read_only_variant",
+    aconfig_declarations: "aconfig.test.flags",
+    mode: "force-read-only",
+}
+
 cc_test {
     name: "aconfig.test.cpp",
     srcs: [
@@ -224,6 +230,21 @@
     test_suites: ["general-tests"],
 }
 
+cc_test {
+    name: "aconfig.test.cpp.force_read_only_mode",
+    srcs: [
+        "tests/aconfig_force_read_only_mode_test.cpp",
+    ],
+    static_libs: [
+        "aconfig_test_cpp_library_force_read_only_variant",
+        "libgmock",
+    ],
+    shared_libs: [
+        "server_configurable_flags",
+    ],
+    test_suites: ["general-tests"],
+}
+
 rust_aconfig_library {
     name: "libaconfig_test_rust_library",
     crate_name: "aconfig_test_rust_library",
diff --git a/tools/aconfig/src/codegen/cpp.rs b/tools/aconfig/src/codegen/cpp.rs
index d6bebba..1279d8e 100644
--- a/tools/aconfig/src/codegen/cpp.rs
+++ b/tools/aconfig/src/codegen/cpp.rs
@@ -51,8 +51,6 @@
         readwrite,
         readwrite_count,
         is_test_mode: codegen_mode == CodegenMode::Test,
-        is_prod_mode: codegen_mode == CodegenMode::Production,
-        is_exported_mode: codegen_mode == CodegenMode::Exported,
         class_elements,
     };
 
@@ -96,8 +94,6 @@
     pub readwrite: bool,
     pub readwrite_count: i32,
     pub is_test_mode: bool,
-    pub is_prod_mode: bool,
-    pub is_exported_mode: bool,
     pub class_elements: Vec<ClassElement>,
 }
 
@@ -485,6 +481,88 @@
 #endif
 "#;
 
+    const EXPORTED_FORCE_READ_ONLY_HEADER_EXPECTED: &str = r#"
+#pragma once
+
+#ifndef COM_ANDROID_ACONFIG_TEST
+#define COM_ANDROID_ACONFIG_TEST(FLAG) COM_ANDROID_ACONFIG_TEST_##FLAG
+#endif
+
+#ifndef COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO
+#define COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO true
+#endif
+
+#ifdef __cplusplus
+
+#include <memory>
+
+namespace com::android::aconfig::test {
+
+class flag_provider_interface {
+public:
+    virtual ~flag_provider_interface() = default;
+
+    virtual bool disabled_ro() = 0;
+
+    virtual bool disabled_rw() = 0;
+
+    virtual bool disabled_rw_in_other_namespace() = 0;
+
+    virtual bool enabled_fixed_ro() = 0;
+
+    virtual bool enabled_ro() = 0;
+
+    virtual bool enabled_rw() = 0;
+};
+
+extern std::unique_ptr<flag_provider_interface> provider_;
+
+inline bool disabled_ro() {
+    return false;
+}
+
+inline bool disabled_rw() {
+    return false;
+}
+
+inline bool disabled_rw_in_other_namespace() {
+    return false;
+}
+
+inline bool enabled_fixed_ro() {
+    return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
+}
+
+inline bool enabled_ro() {
+    return true;
+}
+
+inline bool enabled_rw() {
+    return true;
+}
+
+}
+
+extern "C" {
+#endif // __cplusplus
+
+bool com_android_aconfig_test_disabled_ro();
+
+bool com_android_aconfig_test_disabled_rw();
+
+bool com_android_aconfig_test_disabled_rw_in_other_namespace();
+
+bool com_android_aconfig_test_enabled_fixed_ro();
+
+bool com_android_aconfig_test_enabled_ro();
+
+bool com_android_aconfig_test_enabled_rw();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+"#;
+
     const PROD_SOURCE_FILE_EXPECTED: &str = r#"
 #include "com_android_aconfig_test.h"
 #include <server_configurable_flags/get_flags.h>
@@ -906,6 +984,69 @@
 
 "#;
 
+    const FORCE_READ_ONLY_SOURCE_FILE_EXPECTED: &str = r#"
+#include "com_android_aconfig_test.h"
+
+namespace com::android::aconfig::test {
+
+    class flag_provider : public flag_provider_interface {
+        public:
+
+            virtual bool disabled_ro() override {
+                return false;
+            }
+
+            virtual bool disabled_rw() override {
+                return false;
+            }
+
+            virtual bool disabled_rw_in_other_namespace() override {
+                return false;
+            }
+
+            virtual bool enabled_fixed_ro() override {
+                return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
+            }
+
+            virtual bool enabled_ro() override {
+                return true;
+            }
+
+            virtual bool enabled_rw() override {
+                return true;
+            }
+    };
+
+    std::unique_ptr<flag_provider_interface> provider_ =
+        std::make_unique<flag_provider>();
+}
+
+bool com_android_aconfig_test_disabled_ro() {
+    return false;
+}
+
+bool com_android_aconfig_test_disabled_rw() {
+    return false;
+}
+
+bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
+    return false;
+}
+
+bool com_android_aconfig_test_enabled_fixed_ro() {
+    return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
+}
+
+bool com_android_aconfig_test_enabled_ro() {
+    return true;
+}
+
+bool com_android_aconfig_test_enabled_rw() {
+    return true;
+}
+
+"#;
+
     const READ_ONLY_EXPORTED_PROD_HEADER_EXPECTED: &str = r#"
 #pragma once
 
@@ -1095,6 +1236,17 @@
     }
 
     #[test]
+    fn test_generate_cpp_code_for_force_read_only() {
+        let parsed_flags = crate::test::parse_test_flags();
+        test_generate_cpp_code(
+            parsed_flags,
+            CodegenMode::ForceReadOnly,
+            EXPORTED_FORCE_READ_ONLY_HEADER_EXPECTED,
+            FORCE_READ_ONLY_SOURCE_FILE_EXPECTED,
+        );
+    }
+
+    #[test]
     fn test_generate_cpp_code_for_read_only_prod() {
         let parsed_flags = crate::test::parse_read_only_test_flags();
         test_generate_cpp_code(
diff --git a/tools/aconfig/templates/cpp_exported_header.template b/tools/aconfig/templates/cpp_exported_header.template
index 6b6daa7..0f7853e 100644
--- a/tools/aconfig/templates/cpp_exported_header.template
+++ b/tools/aconfig/templates/cpp_exported_header.template
@@ -44,7 +44,6 @@
     {{ -if is_test_mode }}
     return provider_->{item.flag_name}();
     {{ -else }}
-    {{ -if is_prod_mode }}
     {{ -if item.readwrite }}
     return provider_->{item.flag_name}();
     {{ -else }}
@@ -54,11 +53,6 @@
     return {item.default_value};
     {{ -endif }}
     {{ -endif }}
-    {{ -else }}
-    {{ -if is_exported_mode }}
-    return provider_->{item.flag_name}();
-    {{ -endif }}
-    {{ -endif }}
     {{ -endif }}
 }
 
diff --git a/tools/aconfig/templates/cpp_source_file.template b/tools/aconfig/templates/cpp_source_file.template
index 4aec540..4bcd1b7 100644
--- a/tools/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/templates/cpp_source_file.template
@@ -59,7 +59,6 @@
         {{ -for item in class_elements }}
 
         virtual bool {item.flag_name}() override \{
-            {{ -if is_prod_mode }}
             {{ -if item.readwrite }}
             if (cache_[{item.readwrite_idx}] == -1) \{
                 cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
@@ -75,17 +74,6 @@
             return {item.default_value};
             {{ -endif }}
             {{ -endif }}
-            {{ -else- }}
-            {{ -if is_exported_mode }}
-            if (cache_[{item.readwrite_idx}] == -1) \{
-                cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
-                    "aconfig_flags.{item.device_config_namespace}",
-                    "{item.device_config_flag}",
-                    "false") == "true";
-            }
-            return cache_[{item.readwrite_idx}];
-            {{ -endif }}
-            {{ -endif }}
         }
         {{ -endfor }}
     {{ if readwrite- }}
@@ -106,7 +94,6 @@
     {{ -if is_test_mode }}
     return {cpp_namespace}::{item.flag_name}();
     {{ -else }}
-    {{ -if is_prod_mode }}
     {{ -if item.readwrite }}
     return {cpp_namespace}::{item.flag_name}();
     {{ -else }}
@@ -116,11 +103,6 @@
     return {item.default_value};
     {{ -endif }}
     {{ -endif }}
-    {{ -else }}
-    {{ -if is_exported_mode }}
-    return {cpp_namespace}::{item.flag_name}();
-    {{ -endif }}
-    {{ -endif }}
     {{ -endif }}
 }
 
diff --git a/tools/aconfig/tests/aconfig_force_read_only_mode_test.cpp b/tools/aconfig/tests/aconfig_force_read_only_mode_test.cpp
new file mode 100644
index 0000000..0dec481
--- /dev/null
+++ b/tools/aconfig/tests/aconfig_force_read_only_mode_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include "com_android_aconfig_test.h"
+#include "gtest/gtest.h"
+
+using namespace com::android::aconfig::test;
+
+TEST(AconfigTest, TestDisabledReadOnlyFlag) {
+  ASSERT_FALSE(com_android_aconfig_test_disabled_ro());
+  ASSERT_FALSE(provider_->disabled_ro());
+  ASSERT_FALSE(disabled_ro());
+}
+
+TEST(AconfigTest, TestEnabledReadOnlyFlag) {
+  ASSERT_TRUE(com_android_aconfig_test_enabled_ro());
+  ASSERT_TRUE(provider_->enabled_ro());
+  ASSERT_TRUE(enabled_ro());
+}
+
+TEST(AconfigTest, TestDisabledReadWriteFlag) {
+  ASSERT_FALSE(com_android_aconfig_test_disabled_rw());
+  ASSERT_FALSE(provider_->disabled_rw());
+  ASSERT_FALSE(disabled_rw());
+}
+
+TEST(AconfigTest, TestEnabledReadWriteFlag) {
+  ASSERT_TRUE(com_android_aconfig_test_enabled_rw());
+  ASSERT_TRUE(provider_->enabled_rw());
+  ASSERT_TRUE(enabled_rw());
+}
+
+TEST(AconfigTest, TestEnabledFixedReadOnlyFlag) {
+  ASSERT_TRUE(com_android_aconfig_test_enabled_fixed_ro());
+  ASSERT_TRUE(provider_->enabled_fixed_ro());
+  ASSERT_TRUE(enabled_fixed_ro());
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}