blob: 586ba0480c25acad970ebcb4a1ca12efa57c0f80 [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 Kongstad30950782023-05-09 13:31:29 +020017use anyhow::{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 Kongstad76adff22023-05-08 10:57:24 +020020use serde::{Deserialize, Serialize};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020021use std::fmt;
22use std::io::Read;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020023use std::path::PathBuf;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020024
Mårten Kongstadf02734e2023-06-02 11:34:24 +020025use crate::aconfig::{FlagDeclarations, FlagState, FlagValue, Permission};
26use crate::cache::{Cache, CacheBuilder, Item};
Dennis Shen1dc9ad42023-05-12 00:21:55 +000027use crate::codegen_cpp::generate_cpp_code;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020028use crate::codegen_java::generate_java_code;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020029use crate::codegen_rust::generate_rust_code;
Mårten Kongstad30950782023-05-09 13:31:29 +020030use crate::protos::ProtoParsedFlags;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020031
Mårten Kongstad76adff22023-05-08 10:57:24 +020032#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020033pub enum Source {
34 #[allow(dead_code)] // only used in unit tests
35 Memory,
36 File(String),
37}
38
39impl fmt::Display for Source {
40 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41 match self {
42 Self::Memory => write!(f, "<memory>"),
43 Self::File(path) => write!(f, "{}", path),
44 }
45 }
46}
47
48pub struct Input {
49 pub source: Source,
50 pub reader: Box<dyn Read>,
51}
52
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020053pub struct OutputFile {
54 pub path: PathBuf, // relative to some root directory only main knows about
55 pub contents: Vec<u8>,
56}
57
Mårten Kongstad9fb58962023-05-31 13:02:13 +020058pub fn create_cache(package: &str, declarations: Vec<Input>, values: Vec<Input>) -> Result<Cache> {
59 let mut builder = CacheBuilder::new(package.to_owned())?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020060
Mårten Kongstadfa23d292023-05-11 14:47:02 +020061 for mut input in declarations {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020062 let mut contents = String::new();
63 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020064 let dec_list = FlagDeclarations::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020065 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020066 ensure!(
Mårten Kongstad9fb58962023-05-31 13:02:13 +020067 package == dec_list.package,
68 "Failed to parse {}: expected package {}, got {}",
Mårten Kongstad30950782023-05-09 13:31:29 +020069 input.source,
Mårten Kongstad9fb58962023-05-31 13:02:13 +020070 package,
71 dec_list.package
Mårten Kongstad30950782023-05-09 13:31:29 +020072 );
Mårten Kongstadfa23d292023-05-11 14:47:02 +020073 for d in dec_list.flags.into_iter() {
Mårten Kongstad2f954442023-05-17 16:51:16 +020074 builder.add_flag_declaration(input.source.clone(), d)?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020075 }
76 }
77
Mårten Kongstadfa23d292023-05-11 14:47:02 +020078 for mut input in values {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020079 let mut contents = String::new();
80 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020081 let values_list = FlagValue::try_from_text_proto_list(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020082 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020083 for v in values_list {
84 // TODO: warn about flag values that do not take effect?
Mårten Kongstad2f954442023-05-17 16:51:16 +020085 let _ = builder.add_flag_value(input.source.clone(), v);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020086 }
87 }
88
Mårten Kongstad2f954442023-05-17 16:51:16 +020089 Ok(builder.build())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020090}
91
Mårten Kongstadb27f2ce2023-06-02 11:43:21 +020092pub fn create_java_lib(cache: Cache) -> Result<OutputFile> {
93 generate_java_code(&cache)
Zhi Doueb744892023-05-10 04:02:33 +000094}
95
Mårten Kongstadb27f2ce2023-06-02 11:43:21 +020096pub fn create_cpp_lib(cache: Cache) -> Result<OutputFile> {
97 generate_cpp_code(&cache)
Dennis Shen1dc9ad42023-05-12 00:21:55 +000098}
99
Mårten Kongstadb27f2ce2023-06-02 11:43:21 +0200100pub fn create_rust_lib(cache: Cache) -> Result<OutputFile> {
101 generate_rust_code(&cache)
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200102}
103
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200104pub fn create_device_config_defaults(caches: Vec<Cache>) -> Result<Vec<u8>> {
105 let mut output = Vec::new();
106 for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
107 {
108 let line = format!(
Mårten Kongstad202102f2023-06-08 11:22:44 +0200109 "{}:{}.{}={}\n",
110 item.namespace,
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200111 item.package,
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200112 item.name,
113 match item.state {
114 FlagState::Enabled => "enabled",
115 FlagState::Disabled => "disabled",
116 }
117 );
118 output.extend_from_slice(line.as_bytes());
119 }
120 Ok(output)
121}
122
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200123pub fn create_device_config_sysprops(caches: Vec<Cache>) -> Result<Vec<u8>> {
124 let mut output = Vec::new();
125 for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
126 {
127 let line = format!(
128 "persist.device_config.{}.{}={}\n",
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200129 item.package,
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200130 item.name,
131 match item.state {
132 FlagState::Enabled => "true",
133 FlagState::Disabled => "false",
134 }
135 );
136 output.extend_from_slice(line.as_bytes());
137 }
138 Ok(output)
139}
140
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200141#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200142pub enum DumpFormat {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200143 Text,
144 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +0200145 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200146}
147
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200148pub fn dump_cache(caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
Mårten Kongstadaf677032023-05-17 16:18:25 +0200149 let mut output = Vec::new();
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200150 match format {
151 DumpFormat::Text => {
152 for item in sort_and_iter_items(caches) {
153 let line = format!(
154 "{}/{}: {:?} {:?}\n",
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200155 item.package, item.name, item.state, item.permission
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200156 );
157 output.extend_from_slice(line.as_bytes());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200158 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200159 }
160 DumpFormat::Debug => {
161 for item in sort_and_iter_items(caches) {
162 let line = format!("{:#?}\n", item);
163 output.extend_from_slice(line.as_bytes());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200164 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200165 }
166 DumpFormat::Protobuf => {
167 for cache in sort_and_iter_caches(caches) {
Mårten Kongstadaf677032023-05-17 16:18:25 +0200168 let parsed_flags: ProtoParsedFlags = cache.into();
169 parsed_flags.write_to_vec(&mut output)?;
170 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200171 }
172 }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200173 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200174}
175
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200176fn sort_and_iter_items(caches: Vec<Cache>) -> impl Iterator<Item = Item> {
177 sort_and_iter_caches(caches).flat_map(|cache| cache.into_iter())
178}
179
180fn sort_and_iter_caches(mut caches: Vec<Cache>) -> impl Iterator<Item = Cache> {
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200181 caches.sort_by_cached_key(|cache| cache.package().to_string());
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200182 caches.into_iter()
183}
184
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200185#[cfg(test)]
186mod tests {
187 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200188 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200189
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200190 fn create_test_cache_com_example() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200191 let s = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200192 package: "com.example"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200193 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200194 name: "a"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200195 namespace: "ns"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200196 description: "Description of a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200197 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200198 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200199 name: "b"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200200 namespace: "ns"
Mårten Kongstada1029092023-05-08 11:51:59 +0200201 description: "Description of b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200202 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200203 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200204 let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200205 let o = r#"
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200206 flag_value {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200207 package: "com.example"
Mårten Kongstad30950782023-05-09 13:31:29 +0200208 name: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200209 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200210 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200211 }
212 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200213 let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200214 create_cache("com.example", declarations, values).unwrap()
Mårten Kongstadaf677032023-05-17 16:18:25 +0200215 }
216
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200217 fn create_test_cache_com_other() -> Cache {
Mårten Kongstadaf677032023-05-17 16:18:25 +0200218 let s = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200219 package: "com.other"
Mårten Kongstadaf677032023-05-17 16:18:25 +0200220 flag {
221 name: "c"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200222 namespace: "ns"
Mårten Kongstadaf677032023-05-17 16:18:25 +0200223 description: "Description of c"
224 }
225 "#;
226 let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
227 let o = r#"
228 flag_value {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200229 package: "com.other"
Mårten Kongstadaf677032023-05-17 16:18:25 +0200230 name: "c"
231 state: DISABLED
232 permission: READ_ONLY
233 }
234 "#;
235 let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200236 create_cache("com.other", declarations, values).unwrap()
Mårten Kongstada1029092023-05-08 11:51:59 +0200237 }
238
239 #[test]
240 fn test_create_cache() {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200241 let caches = create_test_cache_com_example(); // calls create_cache
Mårten Kongstadaf677032023-05-17 16:18:25 +0200242 let item = caches.iter().find(|&item| item.name == "a").unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200243 assert_eq!(FlagState::Disabled, item.state);
244 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200245 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200246
247 #[test]
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200248 fn test_create_device_config_defaults() {
249 let caches = vec![crate::test::create_cache()];
250 let bytes = create_device_config_defaults(caches).unwrap();
251 let text = std::str::from_utf8(&bytes).unwrap();
Mårten Kongstad202102f2023-06-08 11:22:44 +0200252 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 +0200253 }
254
255 #[test]
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200256 fn test_create_device_config_sysprops() {
257 let caches = vec![crate::test::create_cache()];
258 let bytes = create_device_config_sysprops(caches).unwrap();
259 let text = std::str::from_utf8(&bytes).unwrap();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200260 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 +0200261 }
262
263 #[test]
Mårten Kongstada1029092023-05-08 11:51:59 +0200264 fn test_dump_text_format() {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200265 let caches = vec![create_test_cache_com_example()];
Mårten Kongstadaf677032023-05-17 16:18:25 +0200266 let bytes = dump_cache(caches, DumpFormat::Text).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200267 let text = std::str::from_utf8(&bytes).unwrap();
268 assert!(text.contains("a: Disabled"));
269 }
270
271 #[test]
272 fn test_dump_protobuf_format() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200273 use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
Mårten Kongstada1029092023-05-08 11:51:59 +0200274 use protobuf::Message;
275
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200276 let caches = vec![create_test_cache_com_example()];
Mårten Kongstadaf677032023-05-17 16:18:25 +0200277 let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
Mårten Kongstad30950782023-05-09 13:31:29 +0200278 let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200279
280 assert_eq!(
281 vec!["a".to_string(), "b".to_string()],
Mårten Kongstad30950782023-05-09 13:31:29 +0200282 actual.parsed_flag.iter().map(|item| item.name.clone().unwrap()).collect::<Vec<_>>()
Mårten Kongstada1029092023-05-08 11:51:59 +0200283 );
Mårten Kongstad30950782023-05-09 13:31:29 +0200284
285 let item =
286 actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200287 assert_eq!(item.package(), "com.example");
Mårten Kongstad30950782023-05-09 13:31:29 +0200288 assert_eq!(item.name(), "b");
289 assert_eq!(item.description(), "Description of b");
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200290 assert_eq!(item.state(), ProtoFlagState::DISABLED);
291 assert_eq!(item.permission(), ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200292 let mut tp = ProtoTracepoint::new();
293 tp.set_source("<memory>".to_string());
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200294 tp.set_state(ProtoFlagState::DISABLED);
295 tp.set_permission(ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200296 assert_eq!(item.trace, vec![tp]);
Mårten Kongstada1029092023-05-08 11:51:59 +0200297 }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200298
299 #[test]
300 fn test_dump_multiple_caches() {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200301 let caches = vec![create_test_cache_com_example(), create_test_cache_com_other()];
Mårten Kongstadaf677032023-05-17 16:18:25 +0200302 let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
303 let dump = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
304 assert_eq!(
305 dump.parsed_flag
306 .iter()
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200307 .map(|parsed_flag| format!("{}/{}", parsed_flag.package(), parsed_flag.name()))
Mårten Kongstadaf677032023-05-17 16:18:25 +0200308 .collect::<Vec<_>>(),
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200309 vec![
310 "com.example/a".to_string(),
311 "com.example/b".to_string(),
312 "com.other/c".to_string()
313 ]
Mårten Kongstadaf677032023-05-17 16:18:25 +0200314 );
315
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200316 let caches = vec![create_test_cache_com_other(), create_test_cache_com_example()];
Mårten Kongstadaf677032023-05-17 16:18:25 +0200317 let bytes = dump_cache(caches, DumpFormat::Protobuf).unwrap();
318 let dump_reversed_input = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
319 assert_eq!(dump, dump_reversed_input);
320 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200321}