1 use crate::load_protos;
2 use crate::{Flag, FlagSource};
3 use crate::{FlagPermission, FlagValue, ValuePickedFrom};
4 use aconfigd_protos::{
5 ProtoFlagQueryReturnMessage, ProtoListStorageMessage, ProtoListStorageMessageMsg,
6 ProtoStorageRequestMessage, ProtoStorageRequestMessageMsg, ProtoStorageRequestMessages,
7 ProtoStorageReturnMessage, ProtoStorageReturnMessageMsg, ProtoStorageReturnMessages,
8 };
9 use anyhow::anyhow;
10 use anyhow::Result;
11 use protobuf::Message;
12 use protobuf::SpecialFields;
13 use std::collections::HashMap;
14 use std::io::{Read, Write};
15 use std::net::Shutdown;
16 use std::os::unix::net::UnixStream;
17
18 pub struct AconfigStorageSource {}
19
20 static ACONFIGD_SYSTEM_SOCKET_NAME: &str = "/dev/socket/aconfigd_system";
21 static ACONFIGD_MAINLINE_SOCKET_NAME: &str = "/dev/socket/aconfigd_mainline";
22
23 enum AconfigdSocket {
24 System,
25 Mainline,
26 }
27
28 impl AconfigdSocket {
name(&self) -> &str29 pub fn name(&self) -> &str {
30 match self {
31 AconfigdSocket::System => ACONFIGD_SYSTEM_SOCKET_NAME,
32 AconfigdSocket::Mainline => ACONFIGD_MAINLINE_SOCKET_NAME,
33 }
34 }
35 }
36
load_flag_to_container() -> Result<HashMap<String, String>>37 fn load_flag_to_container() -> Result<HashMap<String, String>> {
38 Ok(load_protos::load()?.into_iter().map(|p| (p.qualified_name(), p.container)).collect())
39 }
40
convert(msg: ProtoFlagQueryReturnMessage, containers: &HashMap<String, String>) -> Result<Flag>41 fn convert(msg: ProtoFlagQueryReturnMessage, containers: &HashMap<String, String>) -> Result<Flag> {
42 let (value, value_picked_from) = match (
43 &msg.boot_flag_value,
44 msg.default_flag_value,
45 msg.local_flag_value,
46 msg.has_local_override,
47 ) {
48 (_, _, Some(local), Some(has_local)) if has_local => {
49 (FlagValue::try_from(local.as_str())?, ValuePickedFrom::Local)
50 }
51 (Some(boot), Some(default), _, _) => {
52 let value = FlagValue::try_from(boot.as_str())?;
53 if *boot == default {
54 (value, ValuePickedFrom::Default)
55 } else {
56 (value, ValuePickedFrom::Server)
57 }
58 }
59 _ => return Err(anyhow!("missing override")),
60 };
61
62 let staged_value = match (msg.boot_flag_value, msg.server_flag_value, msg.has_server_override) {
63 (Some(boot), Some(server), _) if boot == server => None,
64 (Some(boot), Some(server), Some(has_server)) if boot != server && has_server => {
65 Some(FlagValue::try_from(server.as_str())?)
66 }
67 _ => None,
68 };
69
70 let permission = match msg.is_readwrite {
71 Some(is_readwrite) => {
72 if is_readwrite {
73 FlagPermission::ReadWrite
74 } else {
75 FlagPermission::ReadOnly
76 }
77 }
78 None => return Err(anyhow!("missing permission")),
79 };
80
81 let name = msg.flag_name.ok_or(anyhow!("missing flag name"))?;
82 let package = msg.package_name.ok_or(anyhow!("missing package name"))?;
83 let qualified_name = format!("{package}.{name}");
84 Ok(Flag {
85 name,
86 package,
87 value,
88 permission,
89 value_picked_from,
90 staged_value,
91 container: containers
92 .get(&qualified_name)
93 .cloned()
94 .unwrap_or_else(|| "<no container>".to_string())
95 .to_string(),
96 // TODO: remove once DeviceConfig is not in the CLI.
97 namespace: "-".to_string(),
98 })
99 }
100
read_from_socket(socket: AconfigdSocket) -> Result<Vec<ProtoFlagQueryReturnMessage>>101 fn read_from_socket(socket: AconfigdSocket) -> Result<Vec<ProtoFlagQueryReturnMessage>> {
102 let messages = ProtoStorageRequestMessages {
103 msgs: vec![ProtoStorageRequestMessage {
104 msg: Some(ProtoStorageRequestMessageMsg::ListStorageMessage(ProtoListStorageMessage {
105 msg: Some(ProtoListStorageMessageMsg::All(true)),
106 special_fields: SpecialFields::new(),
107 })),
108 special_fields: SpecialFields::new(),
109 }],
110 special_fields: SpecialFields::new(),
111 };
112
113 let mut socket = UnixStream::connect(socket.name())?;
114
115 let message_buffer = messages.write_to_bytes()?;
116 let mut message_length_buffer: [u8; 4] = [0; 4];
117 let message_size = &message_buffer.len();
118 message_length_buffer[0] = (message_size >> 24) as u8;
119 message_length_buffer[1] = (message_size >> 16) as u8;
120 message_length_buffer[2] = (message_size >> 8) as u8;
121 message_length_buffer[3] = *message_size as u8;
122 socket.write_all(&message_length_buffer)?;
123 socket.write_all(&message_buffer)?;
124 socket.shutdown(Shutdown::Write)?;
125
126 let mut response_length_buffer: [u8; 4] = [0; 4];
127 socket.read_exact(&mut response_length_buffer)?;
128 let response_length = u32::from_be_bytes(response_length_buffer) as usize;
129 let mut response_buffer = vec![0; response_length];
130 socket.read_exact(&mut response_buffer)?;
131
132 let response: ProtoStorageReturnMessages =
133 protobuf::Message::parse_from_bytes(&response_buffer)?;
134
135 match response.msgs.as_slice() {
136 [ProtoStorageReturnMessage {
137 msg: Some(ProtoStorageReturnMessageMsg::ListStorageMessage(list_storage_message)),
138 ..
139 }] => Ok(list_storage_message.flags.clone()),
140 _ => Err(anyhow!("unexpected response from aconfigd")),
141 }
142 }
143
144 impl FlagSource for AconfigStorageSource {
list_flags() -> Result<Vec<Flag>>145 fn list_flags() -> Result<Vec<Flag>> {
146 let containers = load_flag_to_container()?;
147 let system_messages = read_from_socket(AconfigdSocket::System);
148 let mainline_messages = read_from_socket(AconfigdSocket::Mainline);
149
150 let mut all_messages = vec![];
151 if let Ok(system_messages) = system_messages {
152 all_messages.extend_from_slice(&system_messages);
153 }
154 if let Ok(mainline_messages) = mainline_messages {
155 all_messages.extend_from_slice(&mainline_messages);
156 }
157
158 all_messages
159 .into_iter()
160 .map(|query_message| convert(query_message.clone(), &containers))
161 .collect()
162 }
163
override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()>164 fn override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()> {
165 todo!()
166 }
167 }
168