aconfig: move create flag info file api to aconfig_storage_write_api

rust_ffi_static right now will export excessive symbols, this lead to a
duplication of symbols when aconfig links against both
libaconfig_storage_file_cc and libaconfig_storage_read_api_cc. This is
because aconfig_storage_read_api crate depends on aconfig_storage_file
crate. To solve this problem, move create flag info file api to
aconfig_storage_write_api crate which is parallel to
aconfig_storage_read_api crate.

Bug: b/321077378
Test: atest aconfig_storage_file.test; atest
aconfig_storage_read_api.test; atest aconfig_storage_write_api.test

Change-Id: Ibbb50193a2da82d52ccbb4087c8e3fb9f320805f
diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp
index 390067a..b590312 100644
--- a/tools/aconfig/aconfig_storage_file/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/Android.bp
@@ -12,7 +12,6 @@
         "libtempfile",
         "libprotobuf",
         "libclap",
-        "libcxx",
         "libaconfig_storage_protos",
     ],
 }
@@ -70,46 +69,3 @@
     ],
     host_supported: true,
 }
-
-// cxx source codegen from rust api
-genrule {
-    name: "libcxx_aconfig_storage_file_bridge_code",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) > $(out)",
-    srcs: ["src/lib.rs"],
-    out: ["aconfig_storage/lib.rs.cc"],
-}
-
-// cxx header codegen from rust api
-genrule {
-    name: "libcxx_aconfig_storage_file_bridge_header",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) --header > $(out)",
-    srcs: ["src/lib.rs"],
-    out: ["aconfig_storage/lib.rs.h"],
-}
-
-// a static cc lib based on generated code
-rust_ffi_static {
-    name: "libaconfig_storage_file_cxx_bridge",
-    crate_name: "aconfig_storage_file_cxx_bridge",
-    host_supported: true,
-    srcs: ["src/lib.rs"],
-    defaults: ["aconfig_storage_file.defaults"],
-}
-
-// flag storage file cc interface
-cc_library_static {
-    name: "libaconfig_storage_file_cc",
-    srcs: ["aconfig_storage_file.cpp"],
-    generated_headers: [
-        "cxx-bridge-header",
-        "libcxx_aconfig_storage_file_bridge_header",
-    ],
-    generated_sources: ["libcxx_aconfig_storage_file_bridge_code"],
-    whole_static_libs: ["libaconfig_storage_file_cxx_bridge"],
-    export_include_dirs: ["include"],
-    static_libs: [
-        "libbase",
-    ],
-}
diff --git a/tools/aconfig/aconfig_storage_file/Cargo.toml b/tools/aconfig/aconfig_storage_file/Cargo.toml
index 5c51e83..641f481 100644
--- a/tools/aconfig/aconfig_storage_file/Cargo.toml
+++ b/tools/aconfig/aconfig_storage_file/Cargo.toml
@@ -12,7 +12,6 @@
 protobuf = "3.2.0"
 tempfile = "3.9.0"
 thiserror = "1.0.56"
-cxx = "1.0"
 clap = { version = "4.1.8", features = ["derive"] }
 
 [[bin]]
diff --git a/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp b/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp
deleted file mode 100644
index 4807788..0000000
--- a/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "rust/cxx.h"
-#include "aconfig_storage/lib.rs.h"
-#include "aconfig_storage/aconfig_storage_file.hpp"
-
-namespace aconfig_storage {
-android::base::Result<void> create_flag_info(
-    std::string const& package_map,
-    std::string const& flag_map,
-    std::string const& flag_info_out) {
-  auto creation_cxx = create_flag_info_cxx(
-      rust::Str(package_map.c_str()),
-      rust::Str(flag_map.c_str()),
-      rust::Str(flag_info_out.c_str()));
-  if (creation_cxx.success) {
-    return {};
-  } else {
-    return android::base::Error() << creation_cxx.error_message;
-  }
-}
-} // namespace aconfig_storage
diff --git a/tools/aconfig/aconfig_storage_file/build.rs b/tools/aconfig/aconfig_storage_file/build.rs
index 894b71c..1feeb60 100644
--- a/tools/aconfig/aconfig_storage_file/build.rs
+++ b/tools/aconfig/aconfig_storage_file/build.rs
@@ -14,7 +14,4 @@
         .inputs(proto_files)
         .cargo_out_dir("aconfig_storage_protos")
         .run_from_script();
-
-    let _ = cxx_build::bridge("src/lib.rs");
-    println!("cargo:rerun-if-changed=src/lib.rs");
 }
diff --git a/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp b/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp
deleted file mode 100644
index 31af8cd..0000000
--- a/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <string>
-#include <android-base/result.h>
-
-namespace aconfig_storage {
-/// Create flag info file based on package and flag map
-/// \input package_map: package map file
-/// \input flag_map: flag map file
-/// \input flag_info_out: flag info file to be created
-android::base::Result<void> create_flag_info(
-    std::string const& package_map,
-    std::string const& flag_map,
-    std::string const& flag_info_out);
-} // namespace aconfig_storage
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 229c3d5..d14bab6 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -44,16 +44,14 @@
 use std::collections::hash_map::DefaultHasher;
 use std::fs::File;
 use std::hash::{Hash, Hasher};
-use std::io::{Read, Write};
+use std::io::Read;
 
 pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
 pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
 pub use crate::flag_value::{FlagValueHeader, FlagValueList};
 pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
 
-use crate::AconfigStorageError::{
-    BytesParseFail, FileCreationFail, HashTableSizeLimit, InvalidStoredFlagType,
-};
+use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit, InvalidStoredFlagType};
 
 /// Storage file version
 pub const FILE_VERSION: u32 = 1;
@@ -279,104 +277,13 @@
     Ok(flags)
 }
 
-/// Create flag info file
-pub fn create_flag_info(
-    package_map: &str,
-    flag_map: &str,
-    flag_info_out: &str,
-) -> Result<(), AconfigStorageError> {
-    let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
-    let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
-
-    if package_table.header.container != flag_table.header.container {
-        return Err(FileCreationFail(anyhow!(
-            "container for package map {} and flag map {} does not match",
-            package_table.header.container,
-            flag_table.header.container,
-        )));
-    }
-
-    let mut package_offsets = vec![0; package_table.header.num_packages as usize];
-    for node in package_table.nodes.iter() {
-        package_offsets[node.package_id as usize] = node.boolean_offset;
-    }
-
-    let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
-    for node in flag_table.nodes.iter() {
-        let flag_offset = package_offsets[node.package_id as usize] + node.flag_id as u32;
-        is_flag_rw[flag_offset as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
-    }
-
-    let mut list = FlagInfoList {
-        header: FlagInfoHeader {
-            version: FILE_VERSION,
-            container: flag_table.header.container,
-            file_type: StorageFileType::FlagInfo as u8,
-            file_size: 0,
-            num_flags: flag_table.header.num_flags,
-            boolean_flag_offset: 0,
-        },
-        nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
-    };
-
-    list.header.boolean_flag_offset = list.header.into_bytes().len() as u32;
-    list.header.file_size = list.into_bytes().len() as u32;
-
-    let mut file = File::create(flag_info_out).map_err(|errmsg| {
-        FileCreationFail(anyhow!("fail to create file {}: {}", flag_info_out, errmsg))
-    })?;
-    file.write_all(&list.into_bytes()).map_err(|errmsg| {
-        FileCreationFail(anyhow!("fail to write to file {}: {}", flag_info_out, errmsg))
-    })?;
-
-    Ok(())
-}
-
-// *************************************** //
-// CC INTERLOP
-// *************************************** //
-#[cxx::bridge]
-mod ffi {
-    pub struct FlagInfoCreationCXX {
-        pub success: bool,
-        pub error_message: String,
-    }
-
-    extern "Rust" {
-        pub fn create_flag_info_cxx(
-            package_map: &str,
-            flag_map: &str,
-            flag_info_out: &str,
-        ) -> FlagInfoCreationCXX;
-    }
-}
-
-/// Create flag info file cc interlop
-pub fn create_flag_info_cxx(
-    package_map: &str,
-    flag_map: &str,
-    flag_info_out: &str,
-) -> ffi::FlagInfoCreationCXX {
-    match create_flag_info(package_map, flag_map, flag_info_out) {
-        Ok(()) => ffi::FlagInfoCreationCXX {
-            success: true,
-            error_message: String::from(""),
-        },
-        Err(errmsg) => ffi::FlagInfoCreationCXX {
-            success: false,
-            error_message: format!("{:?}", errmsg),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
     use crate::test_utils::{
-        create_test_flag_info_list, create_test_flag_table, create_test_flag_value_list,
-        create_test_package_table, write_bytes_to_temp_file,
+        create_test_flag_table, create_test_flag_value_list, create_test_package_table,
+        write_bytes_to_temp_file,
     };
-    use tempfile::NamedTempFile;
 
     #[test]
     // this test point locks down the flag list api
@@ -445,31 +352,4 @@
         ];
         assert_eq!(flags, expected);
     }
-
-    fn create_empty_temp_file() -> Result<NamedTempFile, AconfigStorageError> {
-        let file = NamedTempFile::new().map_err(|_| {
-            AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
-        })?;
-        Ok(file)
-    }
-
-    #[test]
-    // this test point locks down the flag info creation
-    fn test_create_flag_info() {
-        let package_table =
-            write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
-        let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
-        let flag_info = create_empty_temp_file().unwrap();
-
-        let package_table_path = package_table.path().display().to_string();
-        let flag_table_path = flag_table.path().display().to_string();
-        let flag_info_path = flag_info.path().display().to_string();
-
-        assert!(create_flag_info(&package_table_path, &flag_table_path, &flag_info_path).is_ok());
-
-        let flag_info =
-            FlagInfoList::from_bytes(&read_file_to_bytes(&flag_info_path).unwrap()).unwrap();
-        let expected_flag_info = create_test_flag_info_list();
-        assert_eq!(flag_info, expected_flag_info);
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
index e5155a4..ea88f05 100644
--- a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
+++ b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
@@ -126,4 +126,18 @@
   return {};
 }
 
+Result<void> create_flag_info(
+    std::string const& package_map,
+    std::string const& flag_map,
+    std::string const& flag_info_out) {
+  auto creation_cxx = create_flag_info_cxx(
+      rust::Str(package_map.c_str()),
+      rust::Str(flag_map.c_str()),
+      rust::Str(flag_info_out.c_str()));
+  if (creation_cxx.success) {
+    return {};
+  } else {
+    return android::base::Error() << creation_cxx.error_message;
+  }
+}
 } // namespace aconfig_storage
diff --git a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
index 9e6332a..b652510 100644
--- a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
+++ b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
@@ -34,4 +34,13 @@
     uint32_t offset,
     bool value);
 
+/// Create flag info file based on package and flag map
+/// \input package_map: package map file
+/// \input flag_map: flag map file
+/// \input flag_info_out: flag info file to be created
+Result<void> create_flag_info(
+    std::string const& package_map,
+    std::string const& flag_map,
+    std::string const& flag_info_out);
+
 } // namespace aconfig_storage
diff --git a/tools/aconfig/aconfig_storage_write_api/src/lib.rs b/tools/aconfig/aconfig_storage_write_api/src/lib.rs
index 5562d6a..678bbd5 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/lib.rs
@@ -23,10 +23,15 @@
 #[cfg(test)]
 mod test_utils;
 
-use aconfig_storage_file::AconfigStorageError;
+use aconfig_storage_file::{
+    AconfigStorageError, FlagInfoHeader, FlagInfoList, FlagInfoNode, FlagTable, PackageTable,
+    StorageFileType, StoredFlagType, FILE_VERSION,
+};
 
 use anyhow::anyhow;
 use memmap2::MmapMut;
+use std::fs::File;
+use std::io::{Read, Write};
 
 /// Storage file location pb file
 pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
@@ -65,6 +70,86 @@
     })
 }
 
+/// Read in storage file as bytes
+fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, AconfigStorageError> {
+    let mut file = File::open(file_path).map_err(|errmsg| {
+        AconfigStorageError::FileReadFail(anyhow!("Failed to open file {}: {}", file_path, errmsg))
+    })?;
+    let mut buffer = Vec::new();
+    file.read_to_end(&mut buffer).map_err(|errmsg| {
+        AconfigStorageError::FileReadFail(anyhow!(
+            "Failed to read bytes from file {}: {}",
+            file_path,
+            errmsg
+        ))
+    })?;
+    Ok(buffer)
+}
+
+/// Create flag info file given package map file and flag map file
+/// \input package_map: package map file
+/// \input flag_map: flag map file
+/// \output flag_info_out: created flag info file
+pub fn create_flag_info(
+    package_map: &str,
+    flag_map: &str,
+    flag_info_out: &str,
+) -> Result<(), AconfigStorageError> {
+    let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
+    let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
+
+    if package_table.header.container != flag_table.header.container {
+        return Err(AconfigStorageError::FileCreationFail(anyhow!(
+            "container for package map {} and flag map {} does not match",
+            package_table.header.container,
+            flag_table.header.container,
+        )));
+    }
+
+    let mut package_offsets = vec![0; package_table.header.num_packages as usize];
+    for node in package_table.nodes.iter() {
+        package_offsets[node.package_id as usize] = node.boolean_offset;
+    }
+
+    let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
+    for node in flag_table.nodes.iter() {
+        let flag_offset = package_offsets[node.package_id as usize] + node.flag_id as u32;
+        is_flag_rw[flag_offset as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
+    }
+
+    let mut list = FlagInfoList {
+        header: FlagInfoHeader {
+            version: FILE_VERSION,
+            container: flag_table.header.container,
+            file_type: StorageFileType::FlagInfo as u8,
+            file_size: 0,
+            num_flags: flag_table.header.num_flags,
+            boolean_flag_offset: 0,
+        },
+        nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
+    };
+
+    list.header.boolean_flag_offset = list.header.into_bytes().len() as u32;
+    list.header.file_size = list.into_bytes().len() as u32;
+
+    let mut file = File::create(flag_info_out).map_err(|errmsg| {
+        AconfigStorageError::FileCreationFail(anyhow!(
+            "fail to create file {}: {}",
+            flag_info_out,
+            errmsg
+        ))
+    })?;
+    file.write_all(&list.into_bytes()).map_err(|errmsg| {
+        AconfigStorageError::FileCreationFail(anyhow!(
+            "fail to write to file {}: {}",
+            flag_info_out,
+            errmsg
+        ))
+    })?;
+
+    Ok(())
+}
+
 // *************************************** //
 // CC INTERLOP
 // *************************************** //
@@ -78,6 +163,12 @@
         pub error_message: String,
     }
 
+    // Flag info file creation return for cc interlop
+    pub struct FlagInfoCreationCXX {
+        pub success: bool,
+        pub error_message: String,
+    }
+
     // Rust export to c++
     extern "Rust" {
         pub fn update_boolean_flag_value_cxx(
@@ -85,6 +176,12 @@
             offset: u32,
             value: bool,
         ) -> BooleanFlagValueUpdateCXX;
+
+        pub fn create_flag_info_cxx(
+            package_map: &str,
+            flag_map: &str,
+            flag_info_out: &str,
+        ) -> FlagInfoCreationCXX;
     }
 }
 
@@ -104,14 +201,33 @@
     }
 }
 
+/// Create flag info file cc interlop
+pub(crate) fn create_flag_info_cxx(
+    package_map: &str,
+    flag_map: &str,
+    flag_info_out: &str,
+) -> ffi::FlagInfoCreationCXX {
+    match create_flag_info(package_map, flag_map, flag_info_out) {
+        Ok(()) => ffi::FlagInfoCreationCXX { success: true, error_message: String::from("") },
+        Err(errmsg) => {
+            ffi::FlagInfoCreationCXX { success: false, error_message: format!("{:?}", errmsg) }
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
     use crate::test_utils::copy_to_temp_file;
     use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
+    use aconfig_storage_file::test_utils::{
+        create_test_flag_info_list, create_test_flag_table, create_test_package_table,
+        write_bytes_to_temp_file,
+    };
     use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
     use std::fs::File;
     use std::io::Read;
+    use tempfile::NamedTempFile;
 
     fn get_boolean_flag_value_at_offset(file: &str, offset: u32) -> bool {
         let mut f = File::open(&file).unwrap();
@@ -156,4 +272,31 @@
             }
         }
     }
+
+    fn create_empty_temp_file() -> Result<NamedTempFile, AconfigStorageError> {
+        let file = NamedTempFile::new().map_err(|_| {
+            AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
+        })?;
+        Ok(file)
+    }
+
+    #[test]
+    // this test point locks down the flag info creation
+    fn test_create_flag_info() {
+        let package_table =
+            write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
+        let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
+        let flag_info = create_empty_temp_file().unwrap();
+
+        let package_table_path = package_table.path().display().to_string();
+        let flag_table_path = flag_table.path().display().to_string();
+        let flag_info_path = flag_info.path().display().to_string();
+
+        assert!(create_flag_info(&package_table_path, &flag_table_path, &flag_info_path).is_ok());
+
+        let flag_info =
+            FlagInfoList::from_bytes(&read_file_to_bytes(&flag_info_path).unwrap()).unwrap();
+        let expected_flag_info = create_test_flag_info_list();
+        assert_eq!(flag_info, expected_flag_info);
+    }
 }
diff --git a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
index d2a52fe..5b23dbc 100644
--- a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
@@ -39,4 +39,5 @@
         "device-tests",
         "general-tests",
     ],
+    ldflags: ["-Wl,--allow-multiple-definition"],
 }