Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61d8c5a7 authored by Dennis Shen's avatar Dennis Shen
Browse files

aconfig: split aconfig_storage_file crate

Current aconfig_storage_file crate contains two things: 1,
aconfig storage file definition (which is used by aconfig crate for
storage file creation) and 2, flag storage file read api. With this
change, we are splitting 2 into its own crate aconfig_storage_read_api

In the long run, there will be 3 crates for aconfig_storage

1, aconfig_storage_file
It contains aconfig storage file definition, as well as a binary to help
print/dump aconfig storage binary files into some readable format.

2, aconfig_storage_read_api
This crate contains flag read apis. This crate depends on
aconfig_storge_file crate. This crate will be used by codegen.

3, aconfig_storage_write_api
This crate contains flag write apis. This crate depends on
aconfig_storage_file crate. This crate will only be used by aconfig
daemon to update flag values.

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

Change-Id: Ia6afdc40a45c7c59652fbfd123c2b77bf6666dd9
parent 279e018b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ members = [
    "aconfig",
    "aconfig_protos",
    "aconfig_storage_file",
    "aconfig_storage_read_api",
    "aflags",
    "printflags"
]
+6 −2
Original line number Diff line number Diff line
@@ -69,13 +69,17 @@
    }
  ],
  "postsubmit": [
    {
      // aconfig_storage_read_api unit tests
      "name": "aconfig_storage_read_api.test"
    },
    {
      // aconfig_storage read api rust integration tests
      "name": "aconfig_storage.test.rust"
      "name": "aconfig_storage_read_api.test.rust"
    },
    {
      // aconfig_storage read api cpp integration tests
      "name": "aconfig_storage.test.cpp"
      "name": "aconfig_storage_read_api.test.cpp"
    },
    {
      // aflags CLI unit tests
+0 −89
Original line number Diff line number Diff line
@@ -9,12 +9,6 @@ rust_defaults {
    srcs: ["src/lib.rs"],
    rustlibs: [
        "libanyhow",
        "libaconfig_storage_protos",
        "libonce_cell",
        "libprotobuf",
        "libtempfile",
        "libmemmap2",
        "libcxx",
        "libthiserror",
    ],
}
@@ -26,91 +20,8 @@ rust_library {
    defaults: ["aconfig_storage_file.defaults"],
}

genrule {
    name: "ro.package.map",
    out: ["tests/tmp.ro.package.map"],
    srcs: ["tests/package.map"],
    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
}

genrule {
    name: "ro.flag.map",
    out: ["tests/tmp.ro.flag.map"],
    srcs: ["tests/flag.map"],
    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
}

genrule {
    name: "ro.flag.val",
    out: ["tests/tmp.ro.flag.val"],
    srcs: ["tests/flag.val"],
    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
}

rust_test_host {
    name: "aconfig_storage_file.test",
    test_suites: ["general-tests"],
    defaults: ["aconfig_storage_file.defaults"],
    data: [
        "tests/package.map",
        "tests/flag.map",
        "tests/flag.val",
    ],
}

rust_protobuf {
    name: "libaconfig_storage_protos",
    protos: ["protos/aconfig_storage_metadata.proto"],
    crate_name: "aconfig_storage_protos",
    source_stem: "aconfig_storage_protos",
    host_supported: true,
}

cc_library_static {
    name: "libaconfig_storage_protos_cc",
    proto: {
        export_proto_headers: true,
        type: "lite",
    },
    srcs: ["protos/aconfig_storage_metadata.proto"],
    apex_available: [
        "//apex_available:platform",
        "//apex_available:anyapex",
    ],
    host_supported: true,
}

genrule {
    name: "libcxx_aconfig_storage_bridge_code",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) > $(out)",
    srcs: ["src/lib.rs"],
    out: ["aconfig_storage/lib.rs.cc"],
}

genrule {
    name: "libcxx_aconfig_storage_bridge_header",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) --header > $(out)",
    srcs: ["src/lib.rs"],
    out: ["aconfig_storage/lib.rs.h"],
}

rust_ffi_static {
    name: "libaconfig_storage_cxx_bridge",
    crate_name: "aconfig_storage_cxx_bridge",
    host_supported: true,
    defaults: ["aconfig_storage_file.defaults"],
}

cc_library_static {
    name: "libaconfig_storage_cc",
    srcs: ["aconfig_storage.cpp"],
    generated_headers: [
        "cxx-bridge-header",
        "libcxx_aconfig_storage_bridge_header"
    ],
    generated_sources: ["libcxx_aconfig_storage_bridge_code"],
    whole_static_libs: ["libaconfig_storage_cxx_bridge"],
    export_include_dirs: ["include"],
}
+1 −88
Original line number Diff line number Diff line
@@ -17,10 +17,9 @@
//! flag table module defines the flag table file format and methods for serialization
//! and deserialization

use crate::AconfigStorageError::{self, BytesParseFail, HigherStorageFileVersion};
use crate::AconfigStorageError::{self, BytesParseFail};
use crate::{get_bucket_index, read_str_from_bytes, read_u16_from_bytes, read_u32_from_bytes};
use anyhow::anyhow;
pub type FlagOffset = u16;

/// Flag table header struct
#[derive(PartialEq, Debug)]
@@ -154,44 +153,6 @@ impl FlagTable {
    }
}

/// Query flag within package offset
pub fn find_flag_offset(
    buf: &[u8],
    package_id: u32,
    flag: &str,
) -> Result<Option<FlagOffset>, AconfigStorageError> {
    let interpreted_header = FlagTableHeader::from_bytes(buf)?;
    if interpreted_header.version > crate::FILE_VERSION {
        return Err(HigherStorageFileVersion(anyhow!(
            "Cannot read storage file with a higher version of {} with lib version {}",
            interpreted_header.version,
            crate::FILE_VERSION
        )));
    }

    let num_buckets = (interpreted_header.node_offset - interpreted_header.bucket_offset) / 4;
    let bucket_index = FlagTableNode::find_bucket_index(package_id, flag, num_buckets);

    let mut pos = (interpreted_header.bucket_offset + 4 * bucket_index) as usize;
    let mut flag_node_offset = read_u32_from_bytes(buf, &mut pos)? as usize;
    if flag_node_offset < interpreted_header.node_offset as usize
        || flag_node_offset >= interpreted_header.file_size as usize
    {
        return Ok(None);
    }

    loop {
        let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
        if interpreted_node.package_id == package_id && interpreted_node.flag_name == flag {
            return Ok(Some(interpreted_node.flag_id));
        }
        match interpreted_node.next_offset {
            Some(offset) => flag_node_offset = offset as usize,
            None => return Ok(None),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
@@ -270,52 +231,4 @@ mod tests {
        assert!(reinterpreted_table.is_ok());
        assert_eq!(&flag_table, &reinterpreted_table.unwrap());
    }

    #[test]
    // this test point locks down table query
    fn test_flag_query() {
        let flag_table = create_test_flag_table().as_bytes();
        let baseline = vec![
            (0, "enabled_ro", 1u16),
            (0, "enabled_rw", 2u16),
            (1, "disabled_ro", 0u16),
            (2, "enabled_ro", 1u16),
            (1, "enabled_fixed_ro", 1u16),
            (1, "enabled_ro", 2u16),
            (2, "enabled_fixed_ro", 0u16),
            (0, "disabled_rw", 0u16),
        ];
        for (package_id, flag_name, expected_offset) in baseline.into_iter() {
            let flag_offset =
                find_flag_offset(&flag_table[..], package_id, flag_name).unwrap().unwrap();
            assert_eq!(flag_offset, expected_offset);
        }
    }

    #[test]
    // this test point locks down table query of a non exist flag
    fn test_not_existed_flag_query() {
        let flag_table = create_test_flag_table().as_bytes();
        let flag_offset = find_flag_offset(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
        assert_eq!(flag_offset, None);
        let flag_offset = find_flag_offset(&flag_table[..], 2, "disabled_rw").unwrap();
        assert_eq!(flag_offset, None);
    }

    #[test]
    // this test point locks down query error when file has a higher version
    fn test_higher_version_storage_file() {
        let mut table = create_test_flag_table();
        table.header.version = crate::FILE_VERSION + 1;
        let flag_table = table.as_bytes();
        let error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
        assert_eq!(
            format!("{:?}", error),
            format!(
                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
                crate::FILE_VERSION + 1,
                crate::FILE_VERSION
            )
        );
    }
}
+1 −66
Original line number Diff line number Diff line
@@ -17,9 +17,8 @@
//! flag value module defines the flag value file format and methods for serialization
//! and deserialization

use crate::AconfigStorageError::{self, HigherStorageFileVersion, InvalidStorageFileOffset};
use crate::AconfigStorageError;
use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
use anyhow::anyhow;

/// Flag value header struct
#[derive(PartialEq, Debug)]
@@ -87,31 +86,6 @@ impl FlagValueList {
    }
}

/// Query flag value
pub fn find_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool, AconfigStorageError> {
    let interpreted_header = FlagValueHeader::from_bytes(buf)?;
    if interpreted_header.version > crate::FILE_VERSION {
        return Err(HigherStorageFileVersion(anyhow!(
            "Cannot read storage file with a higher version of {} with lib version {}",
            interpreted_header.version,
            crate::FILE_VERSION
        )));
    }

    let mut head = (interpreted_header.boolean_value_offset + flag_offset) as usize;

    // TODO: right now, there is only boolean flags, with more flag value types added
    // later, the end of boolean flag value section should be updated (b/322826265).
    if head >= interpreted_header.file_size as usize {
        return Err(InvalidStorageFileOffset(anyhow!(
            "Flag value offset goes beyond the end of the file."
        )));
    }

    let val = read_u8_from_bytes(buf, &mut head)?;
    Ok(val == 1)
}

#[cfg(test)]
mod tests {
    use super::*;
@@ -142,43 +116,4 @@ mod tests {
        assert!(reinterpreted_value_list.is_ok());
        assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
    }

    #[test]
    // this test point locks down flag value query
    fn test_flag_value_query() {
        let flag_value_list = create_test_flag_value_list().as_bytes();
        let baseline: Vec<bool> = vec![false, true, false, false, true, true, false, true];
        for (offset, expected_value) in baseline.into_iter().enumerate() {
            let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
            assert_eq!(flag_value, expected_value);
        }
    }

    #[test]
    // this test point locks down query beyond the end of boolean section
    fn test_boolean_out_of_range() {
        let flag_value_list = create_test_flag_value_list().as_bytes();
        let error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
        assert_eq!(
            format!("{:?}", error),
            "InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"
        );
    }

    #[test]
    // this test point locks down query error when file has a higher version
    fn test_higher_version_storage_file() {
        let mut value_list = create_test_flag_value_list();
        value_list.header.version = crate::FILE_VERSION + 1;
        let flag_value = value_list.as_bytes();
        let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
        assert_eq!(
            format!("{:?}", error),
            format!(
                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
                crate::FILE_VERSION + 1,
                crate::FILE_VERSION
            )
        );
    }
}
Loading