1 /*
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
17 use anyhow::Result;
18 use serde::Serialize;
19 use tinytemplate::TinyTemplate;
20
21 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
22
23 use std::collections::HashMap;
24
25 use crate::codegen;
26 use crate::codegen::CodegenMode;
27 use crate::commands::OutputFile;
28
generate_rust_code<I>( package: &str, flag_ids: HashMap<String, u16>, parsed_flags_iter: I, codegen_mode: CodegenMode, allow_instrumentation: bool, ) -> Result<OutputFile> where I: Iterator<Item = ProtoParsedFlag>,29 pub fn generate_rust_code<I>(
30 package: &str,
31 flag_ids: HashMap<String, u16>,
32 parsed_flags_iter: I,
33 codegen_mode: CodegenMode,
34 allow_instrumentation: bool,
35 ) -> Result<OutputFile>
36 where
37 I: Iterator<Item = ProtoParsedFlag>,
38 {
39 let template_flags: Vec<TemplateParsedFlag> = parsed_flags_iter
40 .map(|pf| TemplateParsedFlag::new(package, flag_ids.clone(), &pf))
41 .collect();
42 let has_readwrite = template_flags.iter().any(|item| item.readwrite);
43 let container = (template_flags.first().expect("zero template flags").container).to_string();
44 let context = TemplateContext {
45 package: package.to_string(),
46 template_flags,
47 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
48 has_readwrite,
49 allow_instrumentation,
50 container,
51 };
52 let mut template = TinyTemplate::new();
53 template.add_template(
54 "rust_code_gen",
55 match codegen_mode {
56 CodegenMode::Test => include_str!("../../templates/rust_test.template"),
57 CodegenMode::Exported | CodegenMode::ForceReadOnly | CodegenMode::Production => {
58 include_str!("../../templates/rust.template")
59 }
60 },
61 )?;
62 let contents = template.render("rust_code_gen", &context)?;
63 let path = ["src", "lib.rs"].iter().collect();
64 Ok(OutputFile { contents: contents.into(), path })
65 }
66
67 #[derive(Serialize)]
68 struct TemplateContext {
69 pub package: String,
70 pub template_flags: Vec<TemplateParsedFlag>,
71 pub modules: Vec<String>,
72 pub has_readwrite: bool,
73 pub allow_instrumentation: bool,
74 pub container: String,
75 }
76
77 #[derive(Serialize)]
78 struct TemplateParsedFlag {
79 pub readwrite: bool,
80 pub default_value: String,
81 pub name: String,
82 pub container: String,
83 pub flag_offset: u16,
84 pub device_config_namespace: String,
85 pub device_config_flag: String,
86 }
87
88 impl TemplateParsedFlag {
89 #[allow(clippy::nonminimal_bool)]
new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self90 fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
91 Self {
92 readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
93 default_value: match pf.state() {
94 ProtoFlagState::ENABLED => "true".to_string(),
95 ProtoFlagState::DISABLED => "false".to_string(),
96 },
97 name: pf.name().to_string(),
98 container: pf.container().to_string(),
99 flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
100 device_config_namespace: pf.namespace().to_string(),
101 device_config_flag: codegen::create_device_config_ident(package, pf.name())
102 .expect("values checked at flag parse time"),
103 }
104 }
105 }
106
107 #[cfg(test)]
108 mod tests {
109 use super::*;
110
111 const PROD_EXPECTED: &str = r#"
112 //! codegenerated rust flag lib
113 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
114 use std::path::Path;
115 use std::io::Write;
116 use log::{log, LevelFilter, Level};
117
118 static STORAGE_MIGRATION_MARKER_FILE: &str =
119 "/metadata/aconfig_test_missions/mission_1";
120 static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
121
122 /// flag provider
123 pub struct FlagProvider;
124
125 lazy_static::lazy_static! {
126 /// flag value cache for disabled_rw
127 static ref CACHED_disabled_rw: bool = flags_rust::GetServerConfigurableFlag(
128 "aconfig_flags.aconfig_test",
129 "com.android.aconfig.test.disabled_rw",
130 "false") == "true";
131
132 /// flag value cache for disabled_rw_exported
133 static ref CACHED_disabled_rw_exported: bool = flags_rust::GetServerConfigurableFlag(
134 "aconfig_flags.aconfig_test",
135 "com.android.aconfig.test.disabled_rw_exported",
136 "false") == "true";
137
138 /// flag value cache for disabled_rw_in_other_namespace
139 static ref CACHED_disabled_rw_in_other_namespace: bool = flags_rust::GetServerConfigurableFlag(
140 "aconfig_flags.other_namespace",
141 "com.android.aconfig.test.disabled_rw_in_other_namespace",
142 "false") == "true";
143
144 /// flag value cache for enabled_rw
145 static ref CACHED_enabled_rw: bool = flags_rust::GetServerConfigurableFlag(
146 "aconfig_flags.aconfig_test",
147 "com.android.aconfig.test.enabled_rw",
148 "true") == "true";
149
150 }
151
152 impl FlagProvider {
153 /// query flag disabled_ro
154 pub fn disabled_ro(&self) -> bool {
155 false
156 }
157
158 /// query flag disabled_rw
159 pub fn disabled_rw(&self) -> bool {
160 *CACHED_disabled_rw
161 }
162
163 /// query flag disabled_rw_exported
164 pub fn disabled_rw_exported(&self) -> bool {
165 *CACHED_disabled_rw_exported
166 }
167
168 /// query flag disabled_rw_in_other_namespace
169 pub fn disabled_rw_in_other_namespace(&self) -> bool {
170 *CACHED_disabled_rw_in_other_namespace
171 }
172
173 /// query flag enabled_fixed_ro
174 pub fn enabled_fixed_ro(&self) -> bool {
175 true
176 }
177
178 /// query flag enabled_fixed_ro_exported
179 pub fn enabled_fixed_ro_exported(&self) -> bool {
180 true
181 }
182
183 /// query flag enabled_ro
184 pub fn enabled_ro(&self) -> bool {
185 true
186 }
187
188 /// query flag enabled_ro_exported
189 pub fn enabled_ro_exported(&self) -> bool {
190 true
191 }
192
193 /// query flag enabled_rw
194 pub fn enabled_rw(&self) -> bool {
195 *CACHED_enabled_rw
196 }
197 }
198
199 /// flag provider
200 pub static PROVIDER: FlagProvider = FlagProvider;
201
202 /// query flag disabled_ro
203 #[inline(always)]
204 pub fn disabled_ro() -> bool {
205 false
206 }
207
208 /// query flag disabled_rw
209 #[inline(always)]
210 pub fn disabled_rw() -> bool {
211 PROVIDER.disabled_rw()
212 }
213
214 /// query flag disabled_rw_exported
215 #[inline(always)]
216 pub fn disabled_rw_exported() -> bool {
217 PROVIDER.disabled_rw_exported()
218 }
219
220 /// query flag disabled_rw_in_other_namespace
221 #[inline(always)]
222 pub fn disabled_rw_in_other_namespace() -> bool {
223 PROVIDER.disabled_rw_in_other_namespace()
224 }
225
226 /// query flag enabled_fixed_ro
227 #[inline(always)]
228 pub fn enabled_fixed_ro() -> bool {
229 true
230 }
231
232 /// query flag enabled_fixed_ro_exported
233 #[inline(always)]
234 pub fn enabled_fixed_ro_exported() -> bool {
235 true
236 }
237
238 /// query flag enabled_ro
239 #[inline(always)]
240 pub fn enabled_ro() -> bool {
241 true
242 }
243
244 /// query flag enabled_ro_exported
245 #[inline(always)]
246 pub fn enabled_ro_exported() -> bool {
247 true
248 }
249
250 /// query flag enabled_rw
251 #[inline(always)]
252 pub fn enabled_rw() -> bool {
253 PROVIDER.enabled_rw()
254 }
255 "#;
256
257 const PROD_INSTRUMENTED_EXPECTED: &str = r#"
258 //! codegenerated rust flag lib
259 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
260 use std::path::Path;
261 use std::io::Write;
262 use log::{log, LevelFilter, Level};
263
264 static STORAGE_MIGRATION_MARKER_FILE: &str =
265 "/metadata/aconfig_test_missions/mission_1";
266 static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
267
268 /// flag provider
269 pub struct FlagProvider;
270
271 lazy_static::lazy_static! {
272
273 static ref PACKAGE_OFFSET: Result<Option<u32>, AconfigStorageError> = unsafe {
274 get_mapped_storage_file("system", StorageFileType::PackageMap)
275 .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
276 .map(|context| context.map(|c| c.boolean_start_index))
277 };
278
279 static ref FLAG_VAL_MAP: Result<Mmap, AconfigStorageError> = unsafe {
280 get_mapped_storage_file("system", StorageFileType::FlagVal)
281 };
282 /// flag value cache for disabled_rw
283
284 static ref CACHED_disabled_rw: bool = {
285 let result = flags_rust::GetServerConfigurableFlag(
286 "aconfig_flags.aconfig_test",
287 "com.android.aconfig.test.disabled_rw",
288 "false") == "true";
289
290 if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
291 // This will be called multiple times. Subsequent calls after the first are noops.
292 logger::init(
293 logger::Config::default()
294 .with_tag_on_device(MIGRATION_LOG_TAG)
295 .with_max_level(LevelFilter::Info));
296
297 let aconfig_storage_result = FLAG_VAL_MAP
298 .as_ref()
299 .map_err(|err| format!("failed to get flag val map: {err}"))
300 .and_then(|flag_val_map| {
301 PACKAGE_OFFSET
302 .as_ref()
303 .map_err(|err| format!("failed to get package read offset: {err}"))
304 .and_then(|package_offset| {
305 match package_offset {
306 Some(offset) => {
307 get_boolean_flag_value(&flag_val_map, offset + 1)
308 .map_err(|err| format!("failed to get flag: {err}"))
309 },
310 None => Err("no context found for package 'com.android.aconfig.test'".to_string())
311 }
312 })
313 });
314
315 match aconfig_storage_result {
316 Ok(storage_result) if storage_result == result => {
317 log!(Level::Info, "AconfigTestMission1: success! flag 'disabled_rw' contained correct value. Legacy storage was {result}, new storage was {storage_result}");
318 },
319 Ok(storage_result) => {
320 log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
321 },
322 Err(err) => {
323 log!(Level::Error, "AconfigTestMission1: error: {err}")
324 }
325 }
326 }
327
328 result
329 };
330
331 /// flag value cache for disabled_rw_exported
332
333 static ref CACHED_disabled_rw_exported: bool = {
334 let result = flags_rust::GetServerConfigurableFlag(
335 "aconfig_flags.aconfig_test",
336 "com.android.aconfig.test.disabled_rw_exported",
337 "false") == "true";
338
339 if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
340 // This will be called multiple times. Subsequent calls after the first are noops.
341 logger::init(
342 logger::Config::default()
343 .with_tag_on_device(MIGRATION_LOG_TAG)
344 .with_max_level(LevelFilter::Info));
345
346 let aconfig_storage_result = FLAG_VAL_MAP
347 .as_ref()
348 .map_err(|err| format!("failed to get flag val map: {err}"))
349 .and_then(|flag_val_map| {
350 PACKAGE_OFFSET
351 .as_ref()
352 .map_err(|err| format!("failed to get package read offset: {err}"))
353 .and_then(|package_offset| {
354 match package_offset {
355 Some(offset) => {
356 get_boolean_flag_value(&flag_val_map, offset + 2)
357 .map_err(|err| format!("failed to get flag: {err}"))
358 },
359 None => Err("no context found for package 'com.android.aconfig.test'".to_string())
360 }
361 })
362 });
363
364 match aconfig_storage_result {
365 Ok(storage_result) if storage_result == result => {
366 log!(Level::Info, "AconfigTestMission1: success! flag 'disabled_rw_exported' contained correct value. Legacy storage was {result}, new storage was {storage_result}");
367 },
368 Ok(storage_result) => {
369 log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_exported'. Legacy storage was {result}, new storage was {storage_result}");
370 },
371 Err(err) => {
372 log!(Level::Error, "AconfigTestMission1: error: {err}")
373 }
374 }
375 }
376
377 result
378 };
379
380 /// flag value cache for disabled_rw_in_other_namespace
381
382 static ref CACHED_disabled_rw_in_other_namespace: bool = {
383 let result = flags_rust::GetServerConfigurableFlag(
384 "aconfig_flags.other_namespace",
385 "com.android.aconfig.test.disabled_rw_in_other_namespace",
386 "false") == "true";
387
388 if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
389 // This will be called multiple times. Subsequent calls after the first are noops.
390 logger::init(
391 logger::Config::default()
392 .with_tag_on_device(MIGRATION_LOG_TAG)
393 .with_max_level(LevelFilter::Info));
394
395 let aconfig_storage_result = FLAG_VAL_MAP
396 .as_ref()
397 .map_err(|err| format!("failed to get flag val map: {err}"))
398 .and_then(|flag_val_map| {
399 PACKAGE_OFFSET
400 .as_ref()
401 .map_err(|err| format!("failed to get package read offset: {err}"))
402 .and_then(|package_offset| {
403 match package_offset {
404 Some(offset) => {
405 get_boolean_flag_value(&flag_val_map, offset + 3)
406 .map_err(|err| format!("failed to get flag: {err}"))
407 },
408 None => Err("no context found for package 'com.android.aconfig.test'".to_string())
409 }
410 })
411 });
412
413 match aconfig_storage_result {
414 Ok(storage_result) if storage_result == result => {
415 log!(Level::Info, "AconfigTestMission1: success! flag 'disabled_rw_in_other_namespace' contained correct value. Legacy storage was {result}, new storage was {storage_result}");
416 },
417 Ok(storage_result) => {
418 log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_in_other_namespace'. Legacy storage was {result}, new storage was {storage_result}");
419 },
420 Err(err) => {
421 log!(Level::Error, "AconfigTestMission1: error: {err}")
422 }
423 }
424 }
425
426 result
427 };
428
429 /// flag value cache for enabled_rw
430
431 static ref CACHED_enabled_rw: bool = {
432 let result = flags_rust::GetServerConfigurableFlag(
433 "aconfig_flags.aconfig_test",
434 "com.android.aconfig.test.enabled_rw",
435 "true") == "true";
436
437 if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
438 // This will be called multiple times. Subsequent calls after the first are noops.
439 logger::init(
440 logger::Config::default()
441 .with_tag_on_device(MIGRATION_LOG_TAG)
442 .with_max_level(LevelFilter::Info));
443
444 let aconfig_storage_result = FLAG_VAL_MAP
445 .as_ref()
446 .map_err(|err| format!("failed to get flag val map: {err}"))
447 .and_then(|flag_val_map| {
448 PACKAGE_OFFSET
449 .as_ref()
450 .map_err(|err| format!("failed to get package read offset: {err}"))
451 .and_then(|package_offset| {
452 match package_offset {
453 Some(offset) => {
454 get_boolean_flag_value(&flag_val_map, offset + 8)
455 .map_err(|err| format!("failed to get flag: {err}"))
456 },
457 None => Err("no context found for package 'com.android.aconfig.test'".to_string())
458 }
459 })
460 });
461
462 match aconfig_storage_result {
463 Ok(storage_result) if storage_result == result => {
464 log!(Level::Info, "AconfigTestMission1: success! flag 'enabled_rw' contained correct value. Legacy storage was {result}, new storage was {storage_result}");
465 },
466 Ok(storage_result) => {
467 log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'enabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
468 },
469 Err(err) => {
470 log!(Level::Error, "AconfigTestMission1: error: {err}")
471 }
472 }
473 }
474
475 result
476 };
477
478 }
479
480 impl FlagProvider {
481
482
483 /// query flag disabled_ro
484 pub fn disabled_ro(&self) -> bool {
485 false
486 }
487
488 /// query flag disabled_rw
489 pub fn disabled_rw(&self) -> bool {
490 *CACHED_disabled_rw
491 }
492
493 /// query flag disabled_rw_exported
494 pub fn disabled_rw_exported(&self) -> bool {
495 *CACHED_disabled_rw_exported
496 }
497
498 /// query flag disabled_rw_in_other_namespace
499 pub fn disabled_rw_in_other_namespace(&self) -> bool {
500 *CACHED_disabled_rw_in_other_namespace
501 }
502
503 /// query flag enabled_fixed_ro
504 pub fn enabled_fixed_ro(&self) -> bool {
505 true
506 }
507
508 /// query flag enabled_fixed_ro_exported
509 pub fn enabled_fixed_ro_exported(&self) -> bool {
510 true
511 }
512
513 /// query flag enabled_ro
514 pub fn enabled_ro(&self) -> bool {
515 true
516 }
517
518 /// query flag enabled_ro_exported
519 pub fn enabled_ro_exported(&self) -> bool {
520 true
521 }
522
523 /// query flag enabled_rw
524 pub fn enabled_rw(&self) -> bool {
525 *CACHED_enabled_rw
526 }
527
528
529 }
530
531 /// flag provider
532 pub static PROVIDER: FlagProvider = FlagProvider;
533
534
535 /// query flag disabled_ro
536 #[inline(always)]
537 pub fn disabled_ro() -> bool {
538
539
540 let result = false;
541 if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
542 return result;
543 }
544
545 // This will be called multiple times. Subsequent calls after the first
546 // are noops.
547 logger::init(
548 logger::Config::default()
549 .with_tag_on_device(MIGRATION_LOG_TAG)
550 .with_max_level(LevelFilter::Info),
551 );
552
553 unsafe {
554 let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
555 Ok(file) => file,
556 Err(err) => {
557 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
558 return result;
559 }
560 };
561
562 let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
563 Ok(Some(context)) => context,
564 Ok(None) => {
565 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': did not get context");
566 return result;
567 },
568 Err(err) => {
569 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
570 return result;
571 }
572 };
573 let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
574 Ok(val_map) => val_map,
575 Err(err) => {
576 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
577 return result;
578 }
579 };
580 let value = match get_boolean_flag_value(&flag_val_map, 0 + package_read_context.boolean_start_index) {
581 Ok(val) => val,
582 Err(err) => {
583 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
584 return result;
585 }
586 };
587
588 if result != value {
589 log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'disabled_ro'. Legacy storage was {result}, new storage was {value}");
590 } else {
591 let default_value = false;
592 log!(Level::Info, "AconfigTestMission1: success! flag 'disabled_ro' contained correct value. Legacy storage was {default_value}, new storage was {value}");
593 }
594 }
595
596 result
597
598 }
599
600 /// query flag disabled_rw
601 #[inline(always)]
602 pub fn disabled_rw() -> bool {
603 PROVIDER.disabled_rw()
604 }
605
606 /// query flag disabled_rw_exported
607 #[inline(always)]
608 pub fn disabled_rw_exported() -> bool {
609 PROVIDER.disabled_rw_exported()
610 }
611
612 /// query flag disabled_rw_in_other_namespace
613 #[inline(always)]
614 pub fn disabled_rw_in_other_namespace() -> bool {
615 PROVIDER.disabled_rw_in_other_namespace()
616 }
617
618 /// query flag enabled_fixed_ro
619 #[inline(always)]
620 pub fn enabled_fixed_ro() -> bool {
621
622
623 let result = true;
624 if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
625 return result;
626 }
627
628 // This will be called multiple times. Subsequent calls after the first
629 // are noops.
630 logger::init(
631 logger::Config::default()
632 .with_tag_on_device(MIGRATION_LOG_TAG)
633 .with_max_level(LevelFilter::Info),
634 );
635
636 unsafe {
637 let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
638 Ok(file) => file,
639 Err(err) => {
640 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
641 return result;
642 }
643 };
644
645 let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
646 Ok(Some(context)) => context,
647 Ok(None) => {
648 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': did not get context");
649 return result;
650 },
651 Err(err) => {
652 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
653 return result;
654 }
655 };
656 let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
657 Ok(val_map) => val_map,
658 Err(err) => {
659 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
660 return result;
661 }
662 };
663 let value = match get_boolean_flag_value(&flag_val_map, 4 + package_read_context.boolean_start_index) {
664 Ok(val) => val,
665 Err(err) => {
666 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
667 return result;
668 }
669 };
670
671 if result != value {
672 log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro'. Legacy storage was {result}, new storage was {value}");
673 } else {
674 let default_value = true;
675 log!(Level::Info, "AconfigTestMission1: success! flag 'enabled_fixed_ro' contained correct value. Legacy storage was {default_value}, new storage was {value}");
676 }
677 }
678
679 result
680
681 }
682
683 /// query flag enabled_fixed_ro_exported
684 #[inline(always)]
685 pub fn enabled_fixed_ro_exported() -> bool {
686
687
688 let result = true;
689 if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
690 return result;
691 }
692
693 // This will be called multiple times. Subsequent calls after the first
694 // are noops.
695 logger::init(
696 logger::Config::default()
697 .with_tag_on_device(MIGRATION_LOG_TAG)
698 .with_max_level(LevelFilter::Info),
699 );
700
701 unsafe {
702 let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
703 Ok(file) => file,
704 Err(err) => {
705 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
706 return result;
707 }
708 };
709
710 let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
711 Ok(Some(context)) => context,
712 Ok(None) => {
713 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': did not get context");
714 return result;
715 },
716 Err(err) => {
717 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
718 return result;
719 }
720 };
721 let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
722 Ok(val_map) => val_map,
723 Err(err) => {
724 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
725 return result;
726 }
727 };
728 let value = match get_boolean_flag_value(&flag_val_map, 5 + package_read_context.boolean_start_index) {
729 Ok(val) => val,
730 Err(err) => {
731 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
732 return result;
733 }
734 };
735
736 if result != value {
737 log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro_exported'. Legacy storage was {result}, new storage was {value}");
738 } else {
739 let default_value = true;
740 log!(Level::Info, "AconfigTestMission1: success! flag 'enabled_fixed_ro_exported' contained correct value. Legacy storage was {default_value}, new storage was {value}");
741 }
742 }
743
744 result
745
746 }
747
748 /// query flag enabled_ro
749 #[inline(always)]
750 pub fn enabled_ro() -> bool {
751
752
753 let result = true;
754 if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
755 return result;
756 }
757
758 // This will be called multiple times. Subsequent calls after the first
759 // are noops.
760 logger::init(
761 logger::Config::default()
762 .with_tag_on_device(MIGRATION_LOG_TAG)
763 .with_max_level(LevelFilter::Info),
764 );
765
766 unsafe {
767 let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
768 Ok(file) => file,
769 Err(err) => {
770 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
771 return result;
772 }
773 };
774
775 let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
776 Ok(Some(context)) => context,
777 Ok(None) => {
778 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': did not get context");
779 return result;
780 },
781 Err(err) => {
782 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
783 return result;
784 }
785 };
786 let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
787 Ok(val_map) => val_map,
788 Err(err) => {
789 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
790 return result;
791 }
792 };
793 let value = match get_boolean_flag_value(&flag_val_map, 6 + package_read_context.boolean_start_index) {
794 Ok(val) => val,
795 Err(err) => {
796 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
797 return result;
798 }
799 };
800
801 if result != value {
802 log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro'. Legacy storage was {result}, new storage was {value}");
803 } else {
804 let default_value = true;
805 log!(Level::Info, "AconfigTestMission1: success! flag 'enabled_ro' contained correct value. Legacy storage was {default_value}, new storage was {value}");
806 }
807 }
808
809 result
810
811 }
812
813 /// query flag enabled_ro_exported
814 #[inline(always)]
815 pub fn enabled_ro_exported() -> bool {
816
817
818 let result = true;
819 if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
820 return result;
821 }
822
823 // This will be called multiple times. Subsequent calls after the first
824 // are noops.
825 logger::init(
826 logger::Config::default()
827 .with_tag_on_device(MIGRATION_LOG_TAG)
828 .with_max_level(LevelFilter::Info),
829 );
830
831 unsafe {
832 let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
833 Ok(file) => file,
834 Err(err) => {
835 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
836 return result;
837 }
838 };
839
840 let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
841 Ok(Some(context)) => context,
842 Ok(None) => {
843 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': did not get context");
844 return result;
845 },
846 Err(err) => {
847 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
848 return result;
849 }
850 };
851 let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
852 Ok(val_map) => val_map,
853 Err(err) => {
854 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
855 return result;
856 }
857 };
858 let value = match get_boolean_flag_value(&flag_val_map, 7 + package_read_context.boolean_start_index) {
859 Ok(val) => val,
860 Err(err) => {
861 log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
862 return result;
863 }
864 };
865
866 if result != value {
867 log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro_exported'. Legacy storage was {result}, new storage was {value}");
868 } else {
869 let default_value = true;
870 log!(Level::Info, "AconfigTestMission1: success! flag 'enabled_ro_exported' contained correct value. Legacy storage was {default_value}, new storage was {value}");
871 }
872 }
873
874 result
875
876 }
877
878 /// query flag enabled_rw
879 #[inline(always)]
880 pub fn enabled_rw() -> bool {
881 PROVIDER.enabled_rw()
882 }
883 "#;
884
885 const TEST_EXPECTED: &str = r#"
886 //! codegenerated rust flag lib
887
888 use std::collections::BTreeMap;
889 use std::sync::Mutex;
890
891 /// flag provider
892 pub struct FlagProvider {
893 overrides: BTreeMap<&'static str, bool>,
894 }
895
896 impl FlagProvider {
897 /// query flag disabled_ro
898 pub fn disabled_ro(&self) -> bool {
899 self.overrides.get("disabled_ro").copied().unwrap_or(
900 false
901 )
902 }
903
904 /// set flag disabled_ro
905 pub fn set_disabled_ro(&mut self, val: bool) {
906 self.overrides.insert("disabled_ro", val);
907 }
908
909 /// query flag disabled_rw
910 pub fn disabled_rw(&self) -> bool {
911 self.overrides.get("disabled_rw").copied().unwrap_or(
912 flags_rust::GetServerConfigurableFlag(
913 "aconfig_flags.aconfig_test",
914 "com.android.aconfig.test.disabled_rw",
915 "false") == "true"
916 )
917 }
918
919 /// set flag disabled_rw
920 pub fn set_disabled_rw(&mut self, val: bool) {
921 self.overrides.insert("disabled_rw", val);
922 }
923
924 /// query flag disabled_rw_exported
925 pub fn disabled_rw_exported(&self) -> bool {
926 self.overrides.get("disabled_rw_exported").copied().unwrap_or(
927 flags_rust::GetServerConfigurableFlag(
928 "aconfig_flags.aconfig_test",
929 "com.android.aconfig.test.disabled_rw_exported",
930 "false") == "true"
931 )
932 }
933
934 /// set flag disabled_rw_exported
935 pub fn set_disabled_rw_exported(&mut self, val: bool) {
936 self.overrides.insert("disabled_rw_exported", val);
937 }
938
939 /// query flag disabled_rw_in_other_namespace
940 pub fn disabled_rw_in_other_namespace(&self) -> bool {
941 self.overrides.get("disabled_rw_in_other_namespace").copied().unwrap_or(
942 flags_rust::GetServerConfigurableFlag(
943 "aconfig_flags.other_namespace",
944 "com.android.aconfig.test.disabled_rw_in_other_namespace",
945 "false") == "true"
946 )
947 }
948
949 /// set flag disabled_rw_in_other_namespace
950 pub fn set_disabled_rw_in_other_namespace(&mut self, val: bool) {
951 self.overrides.insert("disabled_rw_in_other_namespace", val);
952 }
953
954 /// query flag enabled_fixed_ro
955 pub fn enabled_fixed_ro(&self) -> bool {
956 self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
957 true
958 )
959 }
960
961 /// set flag enabled_fixed_ro
962 pub fn set_enabled_fixed_ro(&mut self, val: bool) {
963 self.overrides.insert("enabled_fixed_ro", val);
964 }
965
966 /// query flag enabled_fixed_ro_exported
967 pub fn enabled_fixed_ro_exported(&self) -> bool {
968 self.overrides.get("enabled_fixed_ro_exported").copied().unwrap_or(
969 true
970 )
971 }
972
973 /// set flag enabled_fixed_ro_exported
974 pub fn set_enabled_fixed_ro_exported(&mut self, val: bool) {
975 self.overrides.insert("enabled_fixed_ro_exported", val);
976 }
977
978 /// query flag enabled_ro
979 pub fn enabled_ro(&self) -> bool {
980 self.overrides.get("enabled_ro").copied().unwrap_or(
981 true
982 )
983 }
984
985 /// set flag enabled_ro
986 pub fn set_enabled_ro(&mut self, val: bool) {
987 self.overrides.insert("enabled_ro", val);
988 }
989
990 /// query flag enabled_ro_exported
991 pub fn enabled_ro_exported(&self) -> bool {
992 self.overrides.get("enabled_ro_exported").copied().unwrap_or(
993 true
994 )
995 }
996
997 /// set flag enabled_ro_exported
998 pub fn set_enabled_ro_exported(&mut self, val: bool) {
999 self.overrides.insert("enabled_ro_exported", val);
1000 }
1001
1002 /// query flag enabled_rw
1003 pub fn enabled_rw(&self) -> bool {
1004 self.overrides.get("enabled_rw").copied().unwrap_or(
1005 flags_rust::GetServerConfigurableFlag(
1006 "aconfig_flags.aconfig_test",
1007 "com.android.aconfig.test.enabled_rw",
1008 "true") == "true"
1009 )
1010 }
1011
1012 /// set flag enabled_rw
1013 pub fn set_enabled_rw(&mut self, val: bool) {
1014 self.overrides.insert("enabled_rw", val);
1015 }
1016
1017 /// clear all flag overrides
1018 pub fn reset_flags(&mut self) {
1019 self.overrides.clear();
1020 }
1021 }
1022
1023 /// flag provider
1024 pub static PROVIDER: Mutex<FlagProvider> = Mutex::new(
1025 FlagProvider {overrides: BTreeMap::new()}
1026 );
1027
1028 /// query flag disabled_ro
1029 #[inline(always)]
1030 pub fn disabled_ro() -> bool {
1031 PROVIDER.lock().unwrap().disabled_ro()
1032 }
1033
1034 /// set flag disabled_ro
1035 #[inline(always)]
1036 pub fn set_disabled_ro(val: bool) {
1037 PROVIDER.lock().unwrap().set_disabled_ro(val);
1038 }
1039
1040 /// query flag disabled_rw
1041 #[inline(always)]
1042 pub fn disabled_rw() -> bool {
1043 PROVIDER.lock().unwrap().disabled_rw()
1044 }
1045
1046 /// set flag disabled_rw
1047 #[inline(always)]
1048 pub fn set_disabled_rw(val: bool) {
1049 PROVIDER.lock().unwrap().set_disabled_rw(val);
1050 }
1051
1052 /// query flag disabled_rw_exported
1053 #[inline(always)]
1054 pub fn disabled_rw_exported() -> bool {
1055 PROVIDER.lock().unwrap().disabled_rw_exported()
1056 }
1057
1058 /// set flag disabled_rw_exported
1059 #[inline(always)]
1060 pub fn set_disabled_rw_exported(val: bool) {
1061 PROVIDER.lock().unwrap().set_disabled_rw_exported(val);
1062 }
1063
1064 /// query flag disabled_rw_in_other_namespace
1065 #[inline(always)]
1066 pub fn disabled_rw_in_other_namespace() -> bool {
1067 PROVIDER.lock().unwrap().disabled_rw_in_other_namespace()
1068 }
1069
1070 /// set flag disabled_rw_in_other_namespace
1071 #[inline(always)]
1072 pub fn set_disabled_rw_in_other_namespace(val: bool) {
1073 PROVIDER.lock().unwrap().set_disabled_rw_in_other_namespace(val);
1074 }
1075
1076 /// query flag enabled_fixed_ro
1077 #[inline(always)]
1078 pub fn enabled_fixed_ro() -> bool {
1079 PROVIDER.lock().unwrap().enabled_fixed_ro()
1080 }
1081
1082 /// set flag enabled_fixed_ro
1083 #[inline(always)]
1084 pub fn set_enabled_fixed_ro(val: bool) {
1085 PROVIDER.lock().unwrap().set_enabled_fixed_ro(val);
1086 }
1087
1088 /// query flag enabled_fixed_ro_exported
1089 #[inline(always)]
1090 pub fn enabled_fixed_ro_exported() -> bool {
1091 PROVIDER.lock().unwrap().enabled_fixed_ro_exported()
1092 }
1093
1094 /// set flag enabled_fixed_ro_exported
1095 #[inline(always)]
1096 pub fn set_enabled_fixed_ro_exported(val: bool) {
1097 PROVIDER.lock().unwrap().set_enabled_fixed_ro_exported(val);
1098 }
1099
1100 /// query flag enabled_ro
1101 #[inline(always)]
1102 pub fn enabled_ro() -> bool {
1103 PROVIDER.lock().unwrap().enabled_ro()
1104 }
1105
1106 /// set flag enabled_ro
1107 #[inline(always)]
1108 pub fn set_enabled_ro(val: bool) {
1109 PROVIDER.lock().unwrap().set_enabled_ro(val);
1110 }
1111
1112 /// query flag enabled_ro_exported
1113 #[inline(always)]
1114 pub fn enabled_ro_exported() -> bool {
1115 PROVIDER.lock().unwrap().enabled_ro_exported()
1116 }
1117
1118 /// set flag enabled_ro_exported
1119 #[inline(always)]
1120 pub fn set_enabled_ro_exported(val: bool) {
1121 PROVIDER.lock().unwrap().set_enabled_ro_exported(val);
1122 }
1123
1124 /// query flag enabled_rw
1125 #[inline(always)]
1126 pub fn enabled_rw() -> bool {
1127 PROVIDER.lock().unwrap().enabled_rw()
1128 }
1129
1130 /// set flag enabled_rw
1131 #[inline(always)]
1132 pub fn set_enabled_rw(val: bool) {
1133 PROVIDER.lock().unwrap().set_enabled_rw(val);
1134 }
1135
1136 /// clear all flag override
1137 pub fn reset_flags() {
1138 PROVIDER.lock().unwrap().reset_flags()
1139 }
1140 "#;
1141
1142 const EXPORTED_EXPECTED: &str = r#"
1143 //! codegenerated rust flag lib
1144 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
1145 use std::path::Path;
1146 use std::io::Write;
1147 use log::{log, LevelFilter, Level};
1148
1149 static STORAGE_MIGRATION_MARKER_FILE: &str =
1150 "/metadata/aconfig_test_missions/mission_1";
1151 static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
1152
1153 /// flag provider
1154 pub struct FlagProvider;
1155
1156 lazy_static::lazy_static! {
1157 /// flag value cache for disabled_rw_exported
1158 static ref CACHED_disabled_rw_exported: bool = flags_rust::GetServerConfigurableFlag(
1159 "aconfig_flags.aconfig_test",
1160 "com.android.aconfig.test.disabled_rw_exported",
1161 "false") == "true";
1162
1163 /// flag value cache for enabled_fixed_ro_exported
1164 static ref CACHED_enabled_fixed_ro_exported: bool = flags_rust::GetServerConfigurableFlag(
1165 "aconfig_flags.aconfig_test",
1166 "com.android.aconfig.test.enabled_fixed_ro_exported",
1167 "false") == "true";
1168
1169 /// flag value cache for enabled_ro_exported
1170 static ref CACHED_enabled_ro_exported: bool = flags_rust::GetServerConfigurableFlag(
1171 "aconfig_flags.aconfig_test",
1172 "com.android.aconfig.test.enabled_ro_exported",
1173 "false") == "true";
1174
1175 }
1176
1177 impl FlagProvider {
1178 /// query flag disabled_rw_exported
1179 pub fn disabled_rw_exported(&self) -> bool {
1180 *CACHED_disabled_rw_exported
1181 }
1182
1183 /// query flag enabled_fixed_ro_exported
1184 pub fn enabled_fixed_ro_exported(&self) -> bool {
1185 *CACHED_enabled_fixed_ro_exported
1186 }
1187
1188 /// query flag enabled_ro_exported
1189 pub fn enabled_ro_exported(&self) -> bool {
1190 *CACHED_enabled_ro_exported
1191 }
1192 }
1193
1194 /// flag provider
1195 pub static PROVIDER: FlagProvider = FlagProvider;
1196
1197 /// query flag disabled_rw_exported
1198 #[inline(always)]
1199 pub fn disabled_rw_exported() -> bool {
1200 PROVIDER.disabled_rw_exported()
1201 }
1202
1203 /// query flag enabled_fixed_ro_exported
1204 #[inline(always)]
1205 pub fn enabled_fixed_ro_exported() -> bool {
1206 PROVIDER.enabled_fixed_ro_exported()
1207 }
1208
1209 /// query flag enabled_ro_exported
1210 #[inline(always)]
1211 pub fn enabled_ro_exported() -> bool {
1212 PROVIDER.enabled_ro_exported()
1213 }
1214 "#;
1215
1216 const FORCE_READ_ONLY_EXPECTED: &str = r#"
1217 //! codegenerated rust flag lib
1218 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
1219 use std::path::Path;
1220 use std::io::Write;
1221 use log::{log, LevelFilter, Level};
1222
1223 static STORAGE_MIGRATION_MARKER_FILE: &str =
1224 "/metadata/aconfig_test_missions/mission_1";
1225 static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
1226
1227 /// flag provider
1228 pub struct FlagProvider;
1229
1230 impl FlagProvider {
1231 /// query flag disabled_ro
1232 pub fn disabled_ro(&self) -> bool {
1233 false
1234 }
1235
1236 /// query flag disabled_rw
1237 pub fn disabled_rw(&self) -> bool {
1238 false
1239 }
1240
1241 /// query flag disabled_rw_in_other_namespace
1242 pub fn disabled_rw_in_other_namespace(&self) -> bool {
1243 false
1244 }
1245
1246 /// query flag enabled_fixed_ro
1247 pub fn enabled_fixed_ro(&self) -> bool {
1248 true
1249 }
1250
1251 /// query flag enabled_ro
1252 pub fn enabled_ro(&self) -> bool {
1253 true
1254 }
1255
1256 /// query flag enabled_rw
1257 pub fn enabled_rw(&self) -> bool {
1258 true
1259 }
1260 }
1261
1262 /// flag provider
1263 pub static PROVIDER: FlagProvider = FlagProvider;
1264
1265 /// query flag disabled_ro
1266 #[inline(always)]
1267 pub fn disabled_ro() -> bool {
1268 false
1269 }
1270
1271 /// query flag disabled_rw
1272 #[inline(always)]
1273 pub fn disabled_rw() -> bool {
1274 false
1275 }
1276
1277 /// query flag disabled_rw_in_other_namespace
1278 #[inline(always)]
1279 pub fn disabled_rw_in_other_namespace() -> bool {
1280 false
1281 }
1282
1283 /// query flag enabled_fixed_ro
1284 #[inline(always)]
1285 pub fn enabled_fixed_ro() -> bool {
1286 true
1287 }
1288
1289 /// query flag enabled_ro
1290 #[inline(always)]
1291 pub fn enabled_ro() -> bool {
1292 true
1293 }
1294
1295 /// query flag enabled_rw
1296 #[inline(always)]
1297 pub fn enabled_rw() -> bool {
1298 true
1299 }
1300 "#;
1301 use crate::commands::assign_flag_ids;
1302
test_generate_rust_code(mode: CodegenMode, allow_instrumentation: bool, expected: &str)1303 fn test_generate_rust_code(mode: CodegenMode, allow_instrumentation: bool, expected: &str) {
1304 let parsed_flags = crate::test::parse_test_flags();
1305 let modified_parsed_flags =
1306 crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
1307 let flag_ids =
1308 assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
1309 let generated = generate_rust_code(
1310 crate::test::TEST_PACKAGE,
1311 flag_ids,
1312 modified_parsed_flags.into_iter(),
1313 mode,
1314 allow_instrumentation,
1315 )
1316 .unwrap();
1317 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
1318 assert_eq!(
1319 None,
1320 crate::test::first_significant_code_diff(
1321 expected,
1322 &String::from_utf8(generated.contents).unwrap()
1323 )
1324 );
1325 }
1326
1327 #[test]
test_generate_rust_code_for_prod()1328 fn test_generate_rust_code_for_prod() {
1329 test_generate_rust_code(CodegenMode::Production, false, PROD_EXPECTED);
1330 }
1331
1332 #[test]
test_generate_rust_code_for_prod_instrumented()1333 fn test_generate_rust_code_for_prod_instrumented() {
1334 test_generate_rust_code(CodegenMode::Production, true, PROD_INSTRUMENTED_EXPECTED);
1335 }
1336
1337 #[test]
test_generate_rust_code_for_test()1338 fn test_generate_rust_code_for_test() {
1339 test_generate_rust_code(CodegenMode::Test, false, TEST_EXPECTED);
1340 }
1341
1342 #[test]
test_generate_rust_code_for_exported()1343 fn test_generate_rust_code_for_exported() {
1344 test_generate_rust_code(CodegenMode::Exported, false, EXPORTED_EXPECTED);
1345 }
1346
1347 #[test]
test_generate_rust_code_for_force_read_only()1348 fn test_generate_rust_code_for_force_read_only() {
1349 test_generate_rust_code(CodegenMode::ForceReadOnly, false, FORCE_READ_ONLY_EXPECTED);
1350 }
1351 }
1352