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

Commit e7fde3a8 authored by Dennis Shen's avatar Dennis Shen Committed by Gerrit Code Review
Browse files

Merge "aconfig: add top level flag read lib api" into main

parents 96b16f65 14521049
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -13,6 +13,9 @@ rust_defaults {
        "libonce_cell",
        "libprotobuf",
        "libtempfile",
        "libmemmap2",
        "libcxx",
        "libthiserror",
    ],
}

@@ -23,10 +26,60 @@ 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)",
}

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

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

genrule {
    name: "rw.flag.val",
    out: ["tests/tmp.rw.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: [
        ":ro.package.map",
        ":ro.flag.map",
        ":ro.flag.val",
        ":rw.package.map",
        ":rw.flag.map",
        ":rw.flag.val",
    ],
}

rust_protobuf {
+2 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@ memmap2 = "0.8.0"
protobuf = "3.2.0"
once_cell = "1.19.0"
tempfile = "3.9.0"
cxx = "1.0"
thiserror = "1.0.56"

[build-dependencies]
protobuf-codegen = "3.2.0"
+22 −15
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
//! flag table module defines the flag table file format and methods for serialization
//! and deserialization

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

/// Flag table header struct
#[derive(PartialEq, Debug)]
@@ -47,7 +49,7 @@ impl FlagTableHeader {
    }

    /// Deserialize from bytes
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
        let mut head = 0;
        Ok(Self {
            version: read_u32_from_bytes(bytes, &mut head)?,
@@ -85,7 +87,7 @@ impl FlagTableNode {
    }

    /// Deserialize from bytes
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
        let mut head = 0;
        let node = Self {
            package_id: read_u32_from_bytes(bytes, &mut head)?,
@@ -127,7 +129,7 @@ impl FlagTable {
    }

    /// Deserialize from bytes
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
        let header = FlagTableHeader::from_bytes(bytes)?;
        let num_flags = header.num_flags;
        let num_buckets = crate::get_table_size(num_flags)?;
@@ -144,7 +146,8 @@ impl FlagTable {
                head += node.as_bytes().len();
                Ok(node)
            })
            .collect::<Result<Vec<_>>>()?;
            .collect::<Result<Vec<_>, AconfigStorageError>>()
            .map_err(|errmsg| BytesParseFail(anyhow!("fail to parse flag table: {}", errmsg)))?;

        let table = Self { header, buckets, nodes };
        Ok(table)
@@ -152,14 +155,18 @@ impl FlagTable {
}

/// Query flag within package offset
pub fn find_flag_offset(buf: &[u8], package_id: u32, flag: &str) -> Result<Option<u16>> {
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(anyhow!(
        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;
@@ -202,7 +209,7 @@ mod tests {
        }
    }

    pub fn create_test_flag_table() -> Result<FlagTable> {
    pub fn create_test_flag_table() -> FlagTable {
        let header = FlagTableHeader {
            version: crate::FILE_VERSION,
            container: String::from("system"),
@@ -240,13 +247,13 @@ mod tests {
            FlagTableNode::new_expected(2, "enabled_fixed_ro", 1, 0, None),
            FlagTableNode::new_expected(0, "disabled_rw", 1, 0, None),
        ];
        Ok(FlagTable { header, buckets, nodes })
        FlagTable { header, buckets, nodes }
    }

    #[test]
    // this test point locks down the table serialization
    fn test_serialization() {
        let flag_table = create_test_flag_table().unwrap();
        let flag_table = create_test_flag_table();

        let header: &FlagTableHeader = &flag_table.header;
        let reinterpreted_header = FlagTableHeader::from_bytes(&header.as_bytes());
@@ -267,7 +274,7 @@ mod tests {
    #[test]
    // this test point locks down table query
    fn test_flag_query() {
        let flag_table = create_test_flag_table().unwrap().as_bytes();
        let flag_table = create_test_flag_table().as_bytes();
        let baseline = vec![
            (0, "enabled_ro", 1u16),
            (0, "enabled_rw", 2u16),
@@ -288,7 +295,7 @@ mod tests {
    #[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().unwrap().as_bytes();
        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();
@@ -298,14 +305,14 @@ mod tests {
    #[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().unwrap();
        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!(
                "Cannot read storage file with a higher version of {} with lib version {}",
                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
                crate::FILE_VERSION + 1,
                crate::FILE_VERSION
            )
+24 −18
Original line number Diff line number Diff line
@@ -17,8 +17,9 @@
//! flag value module defines the flag value file format and methods for serialization
//! and deserialization

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

/// Flag value header struct
#[derive(PartialEq, Debug)]
@@ -45,7 +46,7 @@ impl FlagValueHeader {
    }

    /// Deserialize from bytes
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
        let mut head = 0;
        Ok(Self {
            version: read_u32_from_bytes(bytes, &mut head)?,
@@ -75,7 +76,7 @@ impl FlagValueList {
    }

    /// Deserialize from bytes
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
        let header = FlagValueHeader::from_bytes(bytes)?;
        let num_flags = header.num_flags;
        let mut head = header.as_bytes().len();
@@ -87,14 +88,14 @@ impl FlagValueList {
}

/// Query flag value
pub fn get_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool> {
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(anyhow!(
        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;
@@ -102,7 +103,9 @@ pub fn get_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool> {
    // 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(anyhow!("Flag value offset goes beyond the end of the file."));
        return Err(InvalidStorageFileOffset(anyhow!(
            "Flag value offset goes beyond the end of the file."
        )));
    }

    let val = read_u8_from_bytes(buf, &mut head)?;
@@ -113,7 +116,7 @@ pub fn get_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool> {
mod tests {
    use super::*;

    pub fn create_test_flag_value_list() -> Result<FlagValueList> {
    pub fn create_test_flag_value_list() -> FlagValueList {
        let header = FlagValueHeader {
            version: crate::FILE_VERSION,
            container: String::from("system"),
@@ -122,13 +125,13 @@ mod tests {
            boolean_value_offset: 26,
        };
        let booleans: Vec<bool> = vec![false, true, false, false, true, true, false, true];
        Ok(FlagValueList { header, booleans })
        FlagValueList { header, booleans }
    }

    #[test]
    // this test point locks down the value list serialization
    fn test_serialization() {
        let flag_value_list = create_test_flag_value_list().unwrap();
        let flag_value_list = create_test_flag_value_list();

        let header: &FlagValueHeader = &flag_value_list.header;
        let reinterpreted_header = FlagValueHeader::from_bytes(&header.as_bytes());
@@ -143,10 +146,10 @@ mod tests {
    #[test]
    // this test point locks down flag value query
    fn test_flag_value_query() {
        let flag_value_list = create_test_flag_value_list().unwrap().as_bytes();
        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 = get_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
            let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
            assert_eq!(flag_value, expected_value);
        }
    }
@@ -154,22 +157,25 @@ mod tests {
    #[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().unwrap().as_bytes();
        let error = get_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
        assert_eq!(format!("{:?}", error), "Flag value offset goes beyond the end of the file.");
        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().unwrap();
        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 = get_boolean_flag_value(&flag_value[..], 4).unwrap_err();
        let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
        assert_eq!(
            format!("{:?}", error),
            format!(
                "Cannot read storage file with a higher version of {} with lib version {}",
                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
                crate::FILE_VERSION + 1,
                crate::FILE_VERSION
            )
+293 −20

File changed.

Preview size limit exceeded, changes collapsed.

Loading