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

Commit 7e272b8b authored by Ted Bauer's avatar Ted Bauer Committed by Gerrit Code Review
Browse files

Merge "Read from new storage in aflags" into main

parents 60f44e93 bbbe0924
Loading
Loading
Loading
Loading
+104 −22
Original line number Diff line number Diff line
use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
use anyhow::{anyhow, Result};

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

pub struct AconfigStorageSource {}

use aconfig_storage_file::protos::ProtoStorageFileInfo;
use aconfig_storage_file::protos::ProtoStorageFiles;
use aconfig_storage_file::FlagValueAndInfoSummary;

static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/storage_records.pb";

fn read_default_values(file_info: ProtoStorageFileInfo) -> Result<HashMap<String, FlagValue>> {
    let package_map =
        file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
    let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
    let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;

    let mut result = HashMap::new();
    for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? {
        let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
        result.insert(listed_flag.package_name + &listed_flag.flag_name, value);
    }
    Ok(result)
}

fn read_next_boot_values(
    listed_flags: &[FlagValueAndInfoSummary],
) -> Result<HashMap<String, FlagValue>> {
    let mut result = HashMap::new();
    for flag in listed_flags {
        result.insert(
            flag.package_name.clone() + &flag.flag_name,
            FlagValue::try_from(flag.flag_value.as_str())?,
        );
    }
    Ok(result)
}

fn reconcile(
    default_values: HashMap<String, FlagValue>,
    next_boot_values: HashMap<String, FlagValue>,
    flags_current_boot: &[FlagValueAndInfoSummary],
    container: &str,
) -> Result<Vec<Flag>> {
    let mut result = Vec::new();
    for listed_flag in flags_current_boot {
        let default_value = default_values
            .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
            .copied();

        let name = listed_flag.flag_name.clone();
        let package = listed_flag.package_name.clone();
        let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
        let container = container.to_string();
        let staged_value = next_boot_values
            .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
            .filter(|&v| value != *v)
            .copied();
        let permission = if listed_flag.is_readwrite {
            FlagPermission::ReadWrite
        } else {
            FlagPermission::ReadOnly
        };
        let value_picked_from = if Some(value) == default_value {
            ValuePickedFrom::Default
        } else {
            ValuePickedFrom::Server
        };

        result.push(Flag {
            name,
            package,
            value,
            container,
            staged_value,
            permission,
            value_picked_from,

            // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
            namespace: "-".to_string(),
        });
    }
    Ok(result)
}

impl FlagSource for AconfigStorageSource {
    fn list_flags() -> Result<Vec<Flag>> {
@@ -20,30 +97,35 @@ impl FlagSource for AconfigStorageSource {
        let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;

        for file_info in storage_file_info.files {
            let package_map =
                file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
            let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
            let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
            let default_values = read_default_values(file_info.clone())?;

            let container =
                file_info.container.ok_or(anyhow!("storage file is missing container"))?;
            let package_map = format!("/metadata/aconfig/maps/{container}.package.map");
            let flag_map = format!("/metadata/aconfig/maps/{container}.flag.map");
            let flag_info = format!("/metadata/aconfig/boot/{container}.info");

            for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)?
            {
                result.push(Flag {
                    name: listed_flag.flag_name,
                    package: listed_flag.package_name,
                    value: FlagValue::try_from(listed_flag.flag_value.as_str())?,
                    container: container.to_string(),
            let flag_val_current_boot = format!("/metadata/aconfig/boot/{container}.val");
            let flag_val_next_boot = format!("/metadata/aconfig/flags/{container}.val");

                    // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
                    namespace: "-".to_string(),
            let flags_next_boot = aconfig_storage_file::list_flags_with_info(
                &package_map,
                &flag_map,
                &flag_val_next_boot,
                &flag_info,
            )?;
            let flags_current_boot = aconfig_storage_file::list_flags_with_info(
                &package_map,
                &flag_map,
                &flag_val_current_boot,
                &flag_info,
            )?;

                    // TODO(b/324436145): Populate with real values once API is available.
                    staged_value: None,
                    permission: FlagPermission::ReadOnly,
                    value_picked_from: ValuePickedFrom::Default,
                });
            }
            let next_boot_values = read_next_boot_values(&flags_next_boot)?;
            let processed_flags =
                reconcile(default_values, next_boot_values, &flags_current_boot, &container)?;

            result.extend(processed_flags);
        }

        Ok(result)
+3 −1
Original line number Diff line number Diff line
@@ -286,7 +286,9 @@ fn main() -> Result<()> {
    let cli = Cli::parse();
    let output = match cli.command {
        Command::List { use_new_storage: true, container } => {
            list(FlagSourceType::AconfigStorage, container).map(Some)
            list(FlagSourceType::AconfigStorage, container)
                .map_err(|_| anyhow!("storage may not be enabled"))
                .map(Some)
        }
        Command::List { use_new_storage: false, container } => {
            list(FlagSourceType::DeviceConfig, container).map(Some)