• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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