blob: bd5b49cb7c52c0cdf2b6ac70b6dd992e32430cfe [file] [log] [blame]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +02001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mårten Kongstad403658f2023-06-14 09:51:56 +020017use anyhow::{bail, ensure, Context, Result};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020018use clap::ValueEnum;
Mårten Kongstada1029092023-05-08 11:51:59 +020019use protobuf::Message;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020020use std::io::Read;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020021use std::path::PathBuf;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020022
Dennis Shen1dc9ad42023-05-12 00:21:55 +000023use crate::codegen_cpp::generate_cpp_code;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020024use crate::codegen_java::generate_java_code;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020025use crate::codegen_rust::generate_rust_code;
Mårten Kongstad403658f2023-06-14 09:51:56 +020026use crate::protos::{
27 ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag, ProtoParsedFlags, ProtoTracepoint,
28};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020029
30pub struct Input {
Mårten Kongstad403658f2023-06-14 09:51:56 +020031 pub source: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020032 pub reader: Box<dyn Read>,
33}
34
Mårten Kongstad403658f2023-06-14 09:51:56 +020035impl Input {
36 fn try_parse_flags(&mut self) -> Result<ProtoParsedFlags> {
37 let mut buffer = Vec::new();
38 self.reader.read_to_end(&mut buffer)?;
39 crate::protos::parsed_flags::try_from_binary_proto(&buffer)
40 }
41}
42
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020043pub struct OutputFile {
44 pub path: PathBuf, // relative to some root directory only main knows about
45 pub contents: Vec<u8>,
46}
47
Mårten Kongstad403658f2023-06-14 09:51:56 +020048const DEFAULT_FLAG_STATE: ProtoFlagState = ProtoFlagState::DISABLED;
49const DEFAULT_FLAG_PERMISSION: ProtoFlagPermission = ProtoFlagPermission::READ_WRITE;
50
51pub fn parse_flags(package: &str, declarations: Vec<Input>, values: Vec<Input>) -> Result<Vec<u8>> {
52 let mut parsed_flags = ProtoParsedFlags::new();
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020053
Mårten Kongstadfa23d292023-05-11 14:47:02 +020054 for mut input in declarations {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020055 let mut contents = String::new();
56 input.reader.read_to_string(&mut contents)?;
Mårten Kongstad403658f2023-06-14 09:51:56 +020057
58 let flag_declarations = crate::protos::flag_declarations::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020059 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020060 ensure!(
Mårten Kongstad403658f2023-06-14 09:51:56 +020061 package == flag_declarations.package(),
Mårten Kongstad9fb58962023-05-31 13:02:13 +020062 "Failed to parse {}: expected package {}, got {}",
Mårten Kongstad30950782023-05-09 13:31:29 +020063 input.source,
Mårten Kongstad9fb58962023-05-31 13:02:13 +020064 package,
Mårten Kongstad403658f2023-06-14 09:51:56 +020065 flag_declarations.package()
Mårten Kongstad30950782023-05-09 13:31:29 +020066 );
Mårten Kongstad403658f2023-06-14 09:51:56 +020067 for mut flag_declaration in flag_declarations.flag.into_iter() {
68 crate::protos::flag_declaration::verify_fields(&flag_declaration)
69 .with_context(|| format!("Failed to parse {}", input.source))?;
70
71 // create ParsedFlag using FlagDeclaration and default values
72 let mut parsed_flag = ProtoParsedFlag::new();
73 parsed_flag.set_package(package.to_string());
74 parsed_flag.set_name(flag_declaration.take_name());
75 parsed_flag.set_namespace(flag_declaration.take_namespace());
76 parsed_flag.set_description(flag_declaration.take_description());
Mårten Kongstad1b8636b2023-06-22 10:12:24 +020077 parsed_flag.bug.append(&mut flag_declaration.bug);
Mårten Kongstad403658f2023-06-14 09:51:56 +020078 parsed_flag.set_state(DEFAULT_FLAG_STATE);
79 parsed_flag.set_permission(DEFAULT_FLAG_PERMISSION);
80 let mut tracepoint = ProtoTracepoint::new();
81 tracepoint.set_source(input.source.clone());
82 tracepoint.set_state(DEFAULT_FLAG_STATE);
83 tracepoint.set_permission(DEFAULT_FLAG_PERMISSION);
84 parsed_flag.trace.push(tracepoint);
85
86 // verify ParsedFlag looks reasonable
87 crate::protos::parsed_flag::verify_fields(&parsed_flag)?;
88
89 // verify ParsedFlag can be added
90 ensure!(
91 parsed_flags.parsed_flag.iter().all(|other| other.name() != parsed_flag.name()),
92 "failed to declare flag {} from {}: flag already declared",
93 parsed_flag.name(),
94 input.source
95 );
96
97 // add ParsedFlag to ParsedFlags
98 parsed_flags.parsed_flag.push(parsed_flag);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020099 }
100 }
101
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200102 for mut input in values {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200103 let mut contents = String::new();
104 input.reader.read_to_string(&mut contents)?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200105 let flag_values = crate::protos::flag_values::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200106 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200107 for flag_value in flag_values.flag_value.into_iter() {
108 crate::protos::flag_value::verify_fields(&flag_value)
109 .with_context(|| format!("Failed to parse {}", input.source))?;
110
111 let Some(parsed_flag) = parsed_flags.parsed_flag.iter_mut().find(|pf| pf.package() == flag_value.package() && pf.name() == flag_value.name()) else {
112 // (silently) skip unknown flags
113 continue;
114 };
115
116 parsed_flag.set_state(flag_value.state());
117 parsed_flag.set_permission(flag_value.permission());
118 let mut tracepoint = ProtoTracepoint::new();
119 tracepoint.set_source(input.source.clone());
120 tracepoint.set_state(flag_value.state());
121 tracepoint.set_permission(flag_value.permission());
122 parsed_flag.trace.push(tracepoint);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200123 }
124 }
125
Mårten Kongstad403658f2023-06-14 09:51:56 +0200126 crate::protos::parsed_flags::verify_fields(&parsed_flags)?;
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200127 let mut output = Vec::new();
Mårten Kongstad403658f2023-06-14 09:51:56 +0200128 parsed_flags.write_to_vec(&mut output)?;
129 Ok(output)
130}
131
132pub fn create_java_lib(mut input: Input) -> Result<Vec<OutputFile>> {
133 let parsed_flags = input.try_parse_flags()?;
134 let Some(package) = find_unique_package(&parsed_flags) else {
135 bail!("no parsed flags, or the parsed flags use different packages");
136 };
137 generate_java_code(package, parsed_flags.parsed_flag.iter())
138}
139
140pub fn create_cpp_lib(mut input: Input) -> Result<OutputFile> {
141 let parsed_flags = input.try_parse_flags()?;
142 let Some(package) = find_unique_package(&parsed_flags) else {
143 bail!("no parsed flags, or the parsed flags use different packages");
144 };
145 generate_cpp_code(package, parsed_flags.parsed_flag.iter())
146}
147
148pub fn create_rust_lib(mut input: Input) -> Result<OutputFile> {
149 let parsed_flags = input.try_parse_flags()?;
150 let Some(package) = find_unique_package(&parsed_flags) else {
151 bail!("no parsed flags, or the parsed flags use different packages");
152 };
153 generate_rust_code(package, parsed_flags.parsed_flag.iter())
154}
155
156pub fn create_device_config_defaults(mut input: Input) -> Result<Vec<u8>> {
157 let parsed_flags = input.try_parse_flags()?;
158 let mut output = Vec::new();
159 for parsed_flag in parsed_flags
160 .parsed_flag
161 .into_iter()
162 .filter(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200163 {
164 let line = format!(
Mårten Kongstad202102f2023-06-08 11:22:44 +0200165 "{}:{}.{}={}\n",
Mårten Kongstad403658f2023-06-14 09:51:56 +0200166 parsed_flag.namespace(),
167 parsed_flag.package(),
168 parsed_flag.name(),
169 match parsed_flag.state() {
170 ProtoFlagState::ENABLED => "enabled",
171 ProtoFlagState::DISABLED => "disabled",
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200172 }
173 );
174 output.extend_from_slice(line.as_bytes());
175 }
176 Ok(output)
177}
178
Mårten Kongstad403658f2023-06-14 09:51:56 +0200179pub fn create_device_config_sysprops(mut input: Input) -> Result<Vec<u8>> {
180 let parsed_flags = input.try_parse_flags()?;
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200181 let mut output = Vec::new();
Mårten Kongstad403658f2023-06-14 09:51:56 +0200182 for parsed_flag in parsed_flags
183 .parsed_flag
184 .into_iter()
185 .filter(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200186 {
187 let line = format!(
188 "persist.device_config.{}.{}={}\n",
Mårten Kongstad403658f2023-06-14 09:51:56 +0200189 parsed_flag.package(),
190 parsed_flag.name(),
191 match parsed_flag.state() {
192 ProtoFlagState::ENABLED => "true",
193 ProtoFlagState::DISABLED => "false",
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200194 }
195 );
196 output.extend_from_slice(line.as_bytes());
197 }
198 Ok(output)
199}
200
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200201#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200202pub enum DumpFormat {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200203 Text,
204 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +0200205 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200206}
207
Mårten Kongstad403658f2023-06-14 09:51:56 +0200208pub fn dump_parsed_flags(mut input: Vec<Input>, format: DumpFormat) -> Result<Vec<u8>> {
209 let individually_parsed_flags: Result<Vec<ProtoParsedFlags>> =
210 input.iter_mut().map(|i| i.try_parse_flags()).collect();
211 let parsed_flags: ProtoParsedFlags =
212 crate::protos::parsed_flags::merge(individually_parsed_flags?)?;
213
Mårten Kongstadaf677032023-05-17 16:18:25 +0200214 let mut output = Vec::new();
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200215 match format {
216 DumpFormat::Text => {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200217 for parsed_flag in parsed_flags.parsed_flag.into_iter() {
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200218 let line = format!(
219 "{}/{}: {:?} {:?}\n",
Mårten Kongstad403658f2023-06-14 09:51:56 +0200220 parsed_flag.package(),
221 parsed_flag.name(),
222 parsed_flag.state(),
223 parsed_flag.permission()
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200224 );
225 output.extend_from_slice(line.as_bytes());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200226 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200227 }
228 DumpFormat::Debug => {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200229 for parsed_flag in parsed_flags.parsed_flag.into_iter() {
230 let line = format!("{:#?}\n", parsed_flag);
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200231 output.extend_from_slice(line.as_bytes());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200232 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200233 }
234 DumpFormat::Protobuf => {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200235 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200236 }
237 }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200238 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200239}
240
Mårten Kongstad403658f2023-06-14 09:51:56 +0200241fn find_unique_package(parsed_flags: &ProtoParsedFlags) -> Option<&str> {
242 let Some(package) = parsed_flags.parsed_flag.first().map(|pf| pf.package()) else {
243 return None;
244 };
245 if parsed_flags.parsed_flag.iter().any(|pf| pf.package() != package) {
246 return None;
247 }
248 Some(package)
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200249}
250
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200251#[cfg(test)]
252mod tests {
253 use super::*;
Mårten Kongstada1029092023-05-08 11:51:59 +0200254
255 #[test]
Mårten Kongstad403658f2023-06-14 09:51:56 +0200256 fn test_parse_flags() {
257 let parsed_flags = crate::test::parse_test_flags(); // calls parse_flags
258 crate::protos::parsed_flags::verify_fields(&parsed_flags).unwrap();
259
260 let enabled_ro =
261 parsed_flags.parsed_flag.iter().find(|pf| pf.name() == "enabled_ro").unwrap();
262 assert!(crate::protos::parsed_flag::verify_fields(enabled_ro).is_ok());
263 assert_eq!("com.android.aconfig.test", enabled_ro.package());
264 assert_eq!("enabled_ro", enabled_ro.name());
265 assert_eq!("This flag is ENABLED + READ_ONLY", enabled_ro.description());
266 assert_eq!(ProtoFlagState::ENABLED, enabled_ro.state());
267 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.permission());
268 assert_eq!(3, enabled_ro.trace.len());
269 assert_eq!("tests/test.aconfig", enabled_ro.trace[0].source());
270 assert_eq!(ProtoFlagState::DISABLED, enabled_ro.trace[0].state());
271 assert_eq!(ProtoFlagPermission::READ_WRITE, enabled_ro.trace[0].permission());
272 assert_eq!("tests/first.values", enabled_ro.trace[1].source());
273 assert_eq!(ProtoFlagState::DISABLED, enabled_ro.trace[1].state());
274 assert_eq!(ProtoFlagPermission::READ_WRITE, enabled_ro.trace[1].permission());
275 assert_eq!("tests/second.values", enabled_ro.trace[2].source());
276 assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state());
277 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission());
278
279 assert_eq!(4, parsed_flags.parsed_flag.len());
280 for pf in parsed_flags.parsed_flag.iter() {
281 let first = pf.trace.first().unwrap();
282 assert_eq!(DEFAULT_FLAG_STATE, first.state());
283 assert_eq!(DEFAULT_FLAG_PERMISSION, first.permission());
284
285 let last = pf.trace.last().unwrap();
286 assert_eq!(pf.state(), last.state());
287 assert_eq!(pf.permission(), last.permission());
288 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200289 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200290
291 #[test]
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200292 fn test_create_device_config_defaults() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200293 let input = parse_test_flags_as_input();
294 let bytes = create_device_config_defaults(input).unwrap();
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200295 let text = std::str::from_utf8(&bytes).unwrap();
Mårten Kongstad202102f2023-06-08 11:22:44 +0200296 assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200297 }
298
299 #[test]
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200300 fn test_create_device_config_sysprops() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200301 let input = parse_test_flags_as_input();
302 let bytes = create_device_config_sysprops(input).unwrap();
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200303 let text = std::str::from_utf8(&bytes).unwrap();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200304 assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200305 }
306
307 #[test]
Mårten Kongstada1029092023-05-08 11:51:59 +0200308 fn test_dump_text_format() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200309 let input = parse_test_flags_as_input();
310 let bytes = dump_parsed_flags(vec![input], DumpFormat::Text).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200311 let text = std::str::from_utf8(&bytes).unwrap();
Mårten Kongstad403658f2023-06-14 09:51:56 +0200312 assert!(text.contains("com.android.aconfig.test/disabled_ro: DISABLED READ_ONLY"));
Mårten Kongstada1029092023-05-08 11:51:59 +0200313 }
314
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200315 #[test]
316 fn test_dump_protobuf_format() {
317 let text_proto = r#"
318parsed_flag {
319 package: "com.android.aconfig.test"
320 name: "disabled_ro"
321 namespace: "aconfig_test"
322 description: "This flag is DISABLED + READ_ONLY"
323 state: DISABLED
324 permission: READ_ONLY
325 trace {
326 source: "tests/test.aconfig"
327 state: DISABLED
328 permission: READ_WRITE
329 }
330 trace {
331 source: "tests/first.values"
332 state: DISABLED
333 permission: READ_ONLY
334 }
335 bug: "123"
336}
337parsed_flag {
338 package: "com.android.aconfig.test"
339 name: "disabled_rw"
340 namespace: "aconfig_test"
341 description: "This flag is DISABLED + READ_WRITE"
342 state: DISABLED
343 permission: READ_WRITE
344 trace {
345 source: "tests/test.aconfig"
346 state: DISABLED
347 permission: READ_WRITE
348 }
349 bug: "456"
350}
351parsed_flag {
352 package: "com.android.aconfig.test"
353 name: "enabled_ro"
354 namespace: "aconfig_test"
355 description: "This flag is ENABLED + READ_ONLY"
356 state: ENABLED
357 permission: READ_ONLY
358 trace {
359 source: "tests/test.aconfig"
360 state: DISABLED
361 permission: READ_WRITE
362 }
363 trace {
364 source: "tests/first.values"
365 state: DISABLED
366 permission: READ_WRITE
367 }
368 trace {
369 source: "tests/second.values"
370 state: ENABLED
371 permission: READ_ONLY
372 }
373 bug: "789"
374 bug: "abc"
375}
376parsed_flag {
377 package: "com.android.aconfig.test"
378 name: "enabled_rw"
379 namespace: "aconfig_test"
380 description: "This flag is ENABLED + READ_WRITE"
381 state: ENABLED
382 permission: READ_WRITE
383 trace {
384 source: "tests/test.aconfig"
385 state: DISABLED
386 permission: READ_WRITE
387 }
388 trace {
389 source: "tests/first.values"
390 state: ENABLED
391 permission: READ_WRITE
392 }
393}
394"#;
395 let expected = protobuf::text_format::parse_from_str::<ProtoParsedFlags>(text_proto)
396 .unwrap()
397 .write_to_bytes()
398 .unwrap();
399
400 let input = parse_test_flags_as_input();
401 let actual = dump_parsed_flags(vec![input], DumpFormat::Protobuf).unwrap();
402
403 assert_eq!(expected, actual);
404 }
405
Mårten Kongstad403658f2023-06-14 09:51:56 +0200406 fn parse_test_flags_as_input() -> Input {
407 let parsed_flags = crate::test::parse_test_flags();
408 let binary_proto = parsed_flags.write_to_bytes().unwrap();
409 let cursor = std::io::Cursor::new(binary_proto);
410 let reader = Box::new(cursor);
411 Input { source: "test.data".to_string(), reader }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200412 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200413}