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