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

Commit 4647c0e1 authored by Dennis Shen's avatar Dennis Shen
Browse files

aconfig: create flag info file write rust api

Bug: b/312444587
Test: atest aconfig_storage_write_api.test; atest
aconfig_storage_write_api.test.rust

Change-Id: Icbedc78ae78b2c7590539f008521c507c2b3df5b
parent 2b92885e
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ impl TryFrom<u8> for StorageFileType {
}

/// Flag type enum as stored by storage file
/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATOBILITY. THE MAX IS U16.
/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY. THE MAX IS U16.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StoredFlagType {
    ReadWriteBoolean = 0,
@@ -124,6 +124,25 @@ impl TryFrom<u16> for StoredFlagType {
    }
}

/// Flag value type enum, one FlagValueType maps to many StoredFlagType
/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FlagValueType {
    Boolean = 0,
}

impl TryFrom<StoredFlagType> for FlagValueType {
    type Error = AconfigStorageError;

    fn try_from(value: StoredFlagType) -> Result<Self, Self::Error> {
        match value {
            StoredFlagType::ReadWriteBoolean => Ok(Self::Boolean),
            StoredFlagType::ReadOnlyBoolean => Ok(Self::Boolean),
            StoredFlagType::FixedReadOnlyBoolean => Ok(Self::Boolean),
        }
    }
}

/// Storage query api error
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ use aconfig_storage_file::protos::{
};

/// Find where storage files are stored for a particular container
fn find_container_storage_location(
pub fn find_container_storage_location(
    location_pb_file: &str,
    container: &str,
) -> Result<ProtoStorageFileInfo, AconfigStorageError> {
+2 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ rust_defaults {
        "libcxx",
        "libthiserror",
        "libaconfig_storage_file",
        "libaconfig_storage_read_api",
    ],
}

@@ -68,7 +69,7 @@ cc_library_static {
    srcs: ["aconfig_storage_write_api.cpp"],
    generated_headers: [
        "cxx-bridge-header",
        "libcxx_aconfig_storage_write_api_bridge_header"
        "libcxx_aconfig_storage_write_api_bridge_header",
    ],
    generated_sources: ["libcxx_aconfig_storage_write_api_bridge_code"],
    whole_static_libs: ["libaconfig_storage_write_api_cxx_bridge"],
+129 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

//! flag info update module defines the flag info file write to mapped bytes

use aconfig_storage_file::{
    read_u8_from_bytes, AconfigStorageError, FlagInfoBit, FlagInfoHeader, FlagValueType,
    FILE_VERSION,
};
use anyhow::anyhow;

fn get_flag_info_offset(
    buf: &mut [u8],
    flag_type: FlagValueType,
    flag_index: u32,
) -> Result<usize, AconfigStorageError> {
    let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
    if interpreted_header.version > FILE_VERSION {
        return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
            "Cannot write to storage file with a higher version of {} with lib version {}",
            interpreted_header.version,
            FILE_VERSION
        )));
    }

    // get byte offset to the flag info
    let head = match flag_type {
        FlagValueType::Boolean => (interpreted_header.boolean_flag_offset + flag_index) as usize,
    };

    if head >= interpreted_header.file_size as usize {
        return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
            "Flag value offset goes beyond the end of the file."
        )));
    }

    Ok(head)
}

fn get_flag_attribute_and_offset(
    buf: &mut [u8],
    flag_type: FlagValueType,
    flag_index: u32,
) -> Result<(u8, usize), AconfigStorageError> {
    let head = get_flag_info_offset(buf, flag_type, flag_index)?;
    let mut pos = head;
    let attribute = read_u8_from_bytes(buf, &mut pos)?;
    Ok((attribute, head))
}

/// Set if flag is sticky
pub fn update_flag_is_sticky(
    buf: &mut [u8],
    flag_type: FlagValueType,
    flag_index: u32,
    value: bool,
) -> Result<(), AconfigStorageError> {
    let (attribute, head) = get_flag_attribute_and_offset(buf, flag_type, flag_index)?;
    let is_sticky = (attribute & (FlagInfoBit::IsSticky as u8)) != 0;
    if is_sticky != value {
        buf[head] = (attribute ^ FlagInfoBit::IsSticky as u8).to_le_bytes()[0];
    }
    Ok(())
}

/// Set if flag has override
pub fn update_flag_has_override(
    buf: &mut [u8],
    flag_type: FlagValueType,
    flag_index: u32,
    value: bool,
) -> Result<(), AconfigStorageError> {
    let (attribute, head) = get_flag_attribute_and_offset(buf, flag_type, flag_index)?;
    let has_override = (attribute & (FlagInfoBit::HasOverride as u8)) != 0;
    if has_override != value {
        buf[head] = (attribute ^ FlagInfoBit::HasOverride as u8).to_le_bytes()[0];
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use aconfig_storage_file::test_utils::create_test_flag_info_list;
    use aconfig_storage_read_api::flag_info_query::find_boolean_flag_attribute;

    #[test]
    // this test point locks down is sticky update
    fn test_update_flag_is_sticky() {
        let flag_info_list = create_test_flag_info_list();
        let mut buf = flag_info_list.into_bytes();
        for i in 0..flag_info_list.header.num_flags {
            update_flag_is_sticky(&mut buf, FlagValueType::Boolean, i, true).unwrap();
            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
            assert!((attribute & (FlagInfoBit::IsSticky as u8)) != 0);
            update_flag_is_sticky(&mut buf, FlagValueType::Boolean, i, false).unwrap();
            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
            assert!((attribute & (FlagInfoBit::IsSticky as u8)) == 0);
        }
    }

    #[test]
    // this test point locks down has override update
    fn test_update_flag_has_override() {
        let flag_info_list = create_test_flag_info_list();
        let mut buf = flag_info_list.into_bytes();
        for i in 0..flag_info_list.header.num_flags {
            update_flag_has_override(&mut buf, FlagValueType::Boolean, i, true).unwrap();
            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
            assert!((attribute & (FlagInfoBit::HasOverride as u8)) != 0);
            update_flag_has_override(&mut buf, FlagValueType::Boolean, i, false).unwrap();
            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
            assert!((attribute & (FlagInfoBit::HasOverride as u8)) == 0);
        }
    }
}
+1 −14
Original line number Diff line number Diff line
@@ -49,20 +49,7 @@ pub fn update_boolean_flag_value(
#[cfg(test)]
mod tests {
    use super::*;
    use aconfig_storage_file::{FlagValueList, StorageFileType};

    pub fn create_test_flag_value_list() -> FlagValueList {
        let header = FlagValueHeader {
            version: FILE_VERSION,
            container: String::from("system"),
            file_type: StorageFileType::FlagVal as u8,
            file_size: 35,
            num_flags: 8,
            boolean_value_offset: 27,
        };
        let booleans: Vec<bool> = vec![false; 8];
        FlagValueList { header, booleans }
    }
    use aconfig_storage_file::test_utils::create_test_flag_value_list;

    #[test]
    // this test point locks down flag value update
Loading