1 use crate::{Flag, FlagPermission, FlagValue, ValuePickedFrom};
2 use aconfig_protos::ProtoFlagPermission as ProtoPermission;
3 use aconfig_protos::ProtoFlagState as ProtoState;
4 use aconfig_protos::ProtoParsedFlag;
5 use aconfig_protos::ProtoParsedFlags;
6 use anyhow::Result;
7 use std::fs;
8 use std::path::Path;
9
10 // TODO(b/329875578): use container field directly instead of inferring.
infer_container(path: &Path) -> String11 fn infer_container(path: &Path) -> String {
12 let path_str = path.to_string_lossy();
13 path_str
14 .strip_prefix("/apex/")
15 .or_else(|| path_str.strip_prefix('/'))
16 .unwrap_or(&path_str)
17 .strip_suffix("/etc/aconfig_flags.pb")
18 .unwrap_or(&path_str)
19 .to_string()
20 }
21
convert_parsed_flag(path: &Path, flag: &ProtoParsedFlag) -> Flag22 fn convert_parsed_flag(path: &Path, flag: &ProtoParsedFlag) -> Flag {
23 let namespace = flag.namespace().to_string();
24 let package = flag.package().to_string();
25 let name = flag.name().to_string();
26
27 let value = match flag.state() {
28 ProtoState::ENABLED => FlagValue::Enabled,
29 ProtoState::DISABLED => FlagValue::Disabled,
30 };
31
32 let permission = match flag.permission() {
33 ProtoPermission::READ_ONLY => FlagPermission::ReadOnly,
34 ProtoPermission::READ_WRITE => FlagPermission::ReadWrite,
35 };
36
37 Flag {
38 namespace,
39 package,
40 name,
41 container: infer_container(path),
42 value,
43 staged_value: None,
44 permission,
45 value_picked_from: ValuePickedFrom::Default,
46 }
47 }
48
load() -> Result<Vec<Flag>>49 pub(crate) fn load() -> Result<Vec<Flag>> {
50 let mut result = Vec::new();
51
52 let paths = aconfig_device_paths::parsed_flags_proto_paths()?;
53 for path in paths {
54 let bytes = fs::read(path.clone())?;
55 let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
56 for flag in parsed_flags.parsed_flag {
57 // TODO(b/334954748): enforce one-container-per-flag invariant.
58 result.push(convert_parsed_flag(&path, &flag));
59 }
60 }
61 Ok(result)
62 }
63