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