1 /*
2  * Copyright (C) 2024 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 crate::storage_files::{FlagSnapshot, StorageFiles};
18 use crate::utils::{get_files_digest, read_pb_from_file, remove_file, write_pb_to_file};
19 use crate::AconfigdError;
20 use aconfigd_protos::{
21     ProtoFlagOverride, ProtoFlagOverrideType, ProtoLocalFlagOverrides, ProtoOTAFlagStagingMessage,
22     ProtoPersistStorageRecord, ProtoPersistStorageRecords,
23 };
24 use log::debug;
25 use std::collections::HashMap;
26 use std::path::{Path, PathBuf};
27 
28 // Storage files manager to manage all the storage files across containers
29 #[derive(Debug)]
30 pub(crate) struct StorageFilesManager {
31     pub root_dir: PathBuf,
32     pub all_storage_files: HashMap<String, StorageFiles>,
33     pub package_to_container: HashMap<String, String>,
34 }
35 
36 impl StorageFilesManager {
37     /// Constructor
new(root_dir: &Path) -> Self38     pub(crate) fn new(root_dir: &Path) -> Self {
39         Self {
40             root_dir: root_dir.to_path_buf(),
41             all_storage_files: HashMap::new(),
42             package_to_container: HashMap::new(),
43         }
44     }
45 
46     /// Get storage files for a container
get_storage_files(&mut self, container: &str) -> Option<&mut StorageFiles>47     fn get_storage_files(&mut self, container: &str) -> Option<&mut StorageFiles> {
48         self.all_storage_files.get_mut(container)
49     }
50 
51     /// Add storage files based on a storage record pb entry
add_storage_files_from_pb( &mut self, pb: &ProtoPersistStorageRecord, ) -> Result<(), AconfigdError>52     pub(crate) fn add_storage_files_from_pb(
53         &mut self,
54         pb: &ProtoPersistStorageRecord,
55     ) -> Result<(), AconfigdError> {
56         if self.all_storage_files.contains_key(pb.container()) {
57             debug!(
58                 "Ignored request to add storage files from pb for {}, already exists",
59                 pb.container()
60             );
61             return Ok(());
62         }
63         self.all_storage_files
64             .insert(String::from(pb.container()), StorageFiles::from_pb(pb, &self.root_dir)?);
65 
66         Ok(())
67     }
68 
69     /// Add a new container's storage files
add_storage_files_from_container( &mut self, container: &str, default_package_map: &Path, default_flag_map: &Path, default_flag_val: &Path, default_flag_info: &Path, ) -> Result<&mut StorageFiles, AconfigdError>70     fn add_storage_files_from_container(
71         &mut self,
72         container: &str,
73         default_package_map: &Path,
74         default_flag_map: &Path,
75         default_flag_val: &Path,
76         default_flag_info: &Path,
77     ) -> Result<&mut StorageFiles, AconfigdError> {
78         if self.all_storage_files.contains_key(container) {
79             debug!(
80                 "Ignored request to add storage files from container {}, already exists",
81                 container
82             );
83         }
84 
85         self.all_storage_files.insert(
86             String::from(container),
87             StorageFiles::from_container(
88                 container,
89                 default_package_map,
90                 default_flag_map,
91                 default_flag_val,
92                 default_flag_info,
93                 &self.root_dir,
94             )?,
95         );
96 
97         self.all_storage_files
98             .get_mut(container)
99             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })
100     }
101 
102     /// Update a container's storage files in the case of container update
update_container_storage_files( &mut self, container: &str, default_package_map: &Path, default_flag_map: &Path, default_flag_val: &Path, default_flag_info: &Path, ) -> Result<(), AconfigdError>103     fn update_container_storage_files(
104         &mut self,
105         container: &str,
106         default_package_map: &Path,
107         default_flag_map: &Path,
108         default_flag_val: &Path,
109         default_flag_info: &Path,
110     ) -> Result<(), AconfigdError> {
111         let mut storage_files = self
112             .get_storage_files(container)
113             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
114 
115         // backup overrides
116         let server_overrides = storage_files.get_all_server_overrides()?;
117         let local_overrides = storage_files.get_all_local_overrides()?;
118 
119         // recreate storage files object
120         storage_files.remove_persist_files()?;
121         self.all_storage_files.remove(container);
122         storage_files = self.add_storage_files_from_container(
123             container,
124             default_package_map,
125             default_flag_map,
126             default_flag_val,
127             default_flag_info,
128         )?;
129 
130         // restage server overrides
131         for f in server_overrides.iter() {
132             let context = storage_files.get_package_flag_context(&f.package_name, &f.flag_name)?;
133             if context.flag_exists {
134                 storage_files.stage_server_override(&context, &f.flag_value)?;
135             }
136         }
137 
138         // restage local overrides
139         let mut new_pb = ProtoLocalFlagOverrides::new();
140         for f in local_overrides.into_iter() {
141             let context =
142                 storage_files.get_package_flag_context(f.package_name(), f.flag_name())?;
143             if context.flag_exists {
144                 storage_files.stage_local_override(&context, f.flag_value())?;
145                 new_pb.overrides.push(f);
146             }
147         }
148         write_pb_to_file::<ProtoLocalFlagOverrides>(
149             &new_pb,
150             &storage_files.storage_record.local_overrides,
151         )?;
152 
153         Ok(())
154     }
155 
156     /// add or update a container's storage files in the case of container update
add_or_update_container_storage_files( &mut self, container: &str, default_package_map: &Path, default_flag_map: &Path, default_flag_val: &Path, default_flag_info: &Path, ) -> Result<(), AconfigdError>157     pub(crate) fn add_or_update_container_storage_files(
158         &mut self,
159         container: &str,
160         default_package_map: &Path,
161         default_flag_map: &Path,
162         default_flag_val: &Path,
163         default_flag_info: &Path,
164     ) -> Result<(), AconfigdError> {
165         match self.get_storage_files(container) {
166             Some(storage_files) => {
167                 let digest = get_files_digest(
168                     &[default_package_map, default_flag_map, default_flag_val, default_flag_info][..],
169                 )?;
170                 if storage_files.storage_record.digest != digest {
171                     self.update_container_storage_files(
172                         container,
173                         default_package_map,
174                         default_flag_map,
175                         default_flag_val,
176                         default_flag_info,
177                     )?;
178                 }
179             }
180             None => {
181                 self.add_storage_files_from_container(
182                     container,
183                     default_package_map,
184                     default_flag_map,
185                     default_flag_val,
186                     default_flag_info,
187                 )?;
188             }
189         }
190 
191         Ok(())
192     }
193 
194     /// Apply all staged server and local overrides
apply_all_staged_overrides( &mut self, container: &str, ) -> Result<(), AconfigdError>195     pub(crate) fn apply_all_staged_overrides(
196         &mut self,
197         container: &str,
198     ) -> Result<(), AconfigdError> {
199         let storage_files = self
200             .get_storage_files(container)
201             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
202         storage_files.apply_all_staged_overrides()?;
203         Ok(())
204     }
205 
206     /// Reset all storage files
reset_all_storage(&mut self) -> Result<(), AconfigdError>207     pub(crate) fn reset_all_storage(&mut self) -> Result<(), AconfigdError> {
208         let all_containers = self.all_storage_files.keys().cloned().collect::<Vec<String>>();
209         for container in all_containers {
210             let storage_files = self
211                 .get_storage_files(&container)
212                 .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
213 
214             let record = storage_files.storage_record.clone();
215             storage_files.remove_persist_files()?;
216             self.all_storage_files.remove(&container);
217 
218             self.add_storage_files_from_container(
219                 &container,
220                 &record.default_package_map,
221                 &record.default_flag_map,
222                 &record.default_flag_val,
223                 &record.default_flag_info,
224             )?;
225         }
226         Ok(())
227     }
228 
229     /// Get container
get_container(&mut self, package: &str) -> Result<Option<String>, AconfigdError>230     fn get_container(&mut self, package: &str) -> Result<Option<String>, AconfigdError> {
231         match self.package_to_container.get(package) {
232             Some(container) => Ok(Some(container.clone())),
233             None => {
234                 for (container, storage_files) in &mut self.all_storage_files {
235                     if storage_files.has_package(package)? {
236                         self.package_to_container.insert(String::from(package), container.clone());
237                         return Ok(Some(container.clone()));
238                     }
239                 }
240                 Ok(None)
241             }
242         }
243     }
244 
245     /// Apply flag override
override_flag_value( &mut self, package: &str, flag: &str, value: &str, override_type: ProtoFlagOverrideType, ) -> Result<(), AconfigdError>246     pub(crate) fn override_flag_value(
247         &mut self,
248         package: &str,
249         flag: &str,
250         value: &str,
251         override_type: ProtoFlagOverrideType,
252     ) -> Result<(), AconfigdError> {
253         let container = self
254             .get_container(package)?
255             .ok_or(AconfigdError::FailToFindContainer { package: package.to_string() })?;
256 
257         let storage_files = self
258             .get_storage_files(&container)
259             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
260 
261         let context = storage_files.get_package_flag_context(package, flag)?;
262         match override_type {
263             ProtoFlagOverrideType::SERVER_ON_REBOOT => {
264                 storage_files.stage_server_override(&context, value)?;
265             }
266             ProtoFlagOverrideType::LOCAL_ON_REBOOT => {
267                 storage_files.stage_local_override(&context, value)?;
268             }
269             ProtoFlagOverrideType::LOCAL_IMMEDIATE => {
270                 storage_files.stage_and_apply_local_override(&context, value)?;
271             }
272         }
273 
274         Ok(())
275     }
276 
277     /// Read staged ota flags
get_ota_flags(&mut self) -> Result<Option<Vec<ProtoFlagOverride>>, AconfigdError>278     fn get_ota_flags(&mut self) -> Result<Option<Vec<ProtoFlagOverride>>, AconfigdError> {
279         let ota_pb_file = self.root_dir.join("flags/ota.pb");
280         if !ota_pb_file.exists() {
281             return Ok(None);
282         }
283 
284         let ota_flags_pb = read_pb_from_file::<ProtoOTAFlagStagingMessage>(&ota_pb_file)?;
285         if let Some(target_build_id) = ota_flags_pb.build_id {
286             let device_build_id = rustutils::system_properties::read("ro.build.fingerprint")
287                 .map_err(|errmsg| AconfigdError::FailToReadBuildFingerPrint { errmsg })?;
288             if device_build_id == Some(target_build_id) {
289                 remove_file(&ota_pb_file)?;
290                 Ok(Some(ota_flags_pb.overrides))
291             } else {
292                 Ok(None)
293             }
294         } else {
295             remove_file(&ota_pb_file)?;
296             return Ok(None);
297         }
298     }
299 
300     /// Apply staged ota flags
apply_staged_ota_flags(&mut self) -> Result<(), AconfigdError>301     pub(crate) fn apply_staged_ota_flags(&mut self) -> Result<(), AconfigdError> {
302         if let Some(flags) = self.get_ota_flags()? {
303             for flag in flags.iter() {
304                 if let Err(errmsg) = self.override_flag_value(
305                     flag.package_name(),
306                     flag.flag_name(),
307                     flag.flag_value(),
308                     ProtoFlagOverrideType::SERVER_ON_REBOOT,
309                 ) {
310                     debug!(
311                         "failed to apply ota flag override for {}.{}: {:?}",
312                         flag.package_name(),
313                         flag.flag_name(),
314                         errmsg
315                     );
316                 }
317             }
318         }
319         Ok(())
320     }
321 
322     /// Write persist storage records to file
write_persist_storage_records_to_file( &self, file: &Path, ) -> Result<(), AconfigdError>323     pub(crate) fn write_persist_storage_records_to_file(
324         &self,
325         file: &Path,
326     ) -> Result<(), AconfigdError> {
327         let mut pb = ProtoPersistStorageRecords::new();
328         pb.records = self
329             .all_storage_files
330             .values()
331             .map(|storage_files| {
332                 let record = &storage_files.storage_record;
333                 let mut entry = ProtoPersistStorageRecord::new();
334                 entry.set_version(record.version);
335                 entry.set_container(record.container.clone());
336                 entry.set_package_map(record.default_package_map.display().to_string());
337                 entry.set_flag_map(record.default_flag_map.display().to_string());
338                 entry.set_flag_val(record.default_flag_val.display().to_string());
339                 entry.set_flag_info(record.default_flag_info.display().to_string());
340                 entry.set_digest(record.digest.clone());
341                 entry
342             })
343             .collect();
344         write_pb_to_file(&pb, file)
345     }
346 
347     /// Remove a single local override
remove_local_override( &mut self, package: &str, flag: &str, ) -> Result<(), AconfigdError>348     pub(crate) fn remove_local_override(
349         &mut self,
350         package: &str,
351         flag: &str,
352     ) -> Result<(), AconfigdError> {
353         let container = self
354             .get_container(package)?
355             .ok_or(AconfigdError::FailToFindContainer { package: package.to_string() })?;
356 
357         let storage_files = self
358             .get_storage_files(&container)
359             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
360 
361         let context = storage_files.get_package_flag_context(package, flag)?;
362         storage_files.remove_local_override(&context)
363     }
364 
365     /// Remove all local overrides
remove_all_local_overrides(&mut self) -> Result<(), AconfigdError>366     pub(crate) fn remove_all_local_overrides(&mut self) -> Result<(), AconfigdError> {
367         for storage_files in self.all_storage_files.values_mut() {
368             storage_files.remove_all_local_overrides()?;
369         }
370         Ok(())
371     }
372 
373     /// Get flag snapshot
get_flag_snapshot( &mut self, package: &str, flag: &str, ) -> Result<Option<FlagSnapshot>, AconfigdError>374     pub(crate) fn get_flag_snapshot(
375         &mut self,
376         package: &str,
377         flag: &str,
378     ) -> Result<Option<FlagSnapshot>, AconfigdError> {
379         match self.get_container(package)? {
380             Some(container) => {
381                 let storage_files = self.get_storage_files(&container).ok_or(
382                     AconfigdError::FailToGetStorageFiles { container: container.to_string() },
383                 )?;
384 
385                 storage_files.get_flag_snapshot(package, flag)
386             }
387             None => Ok(None),
388         }
389     }
390 
391     /// List all flags in a package
list_flags_in_package( &mut self, package: &str, ) -> Result<Vec<FlagSnapshot>, AconfigdError>392     pub(crate) fn list_flags_in_package(
393         &mut self,
394         package: &str,
395     ) -> Result<Vec<FlagSnapshot>, AconfigdError> {
396         let container = self
397             .get_container(package)?
398             .ok_or(AconfigdError::FailToFindContainer { package: package.to_string() })?;
399 
400         let storage_files = self
401             .get_storage_files(&container)
402             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
403 
404         storage_files.list_flags_in_package(package)
405     }
406 
407     /// List flags in a container
list_flags_in_container( &mut self, container: &str, ) -> Result<Vec<FlagSnapshot>, AconfigdError>408     pub(crate) fn list_flags_in_container(
409         &mut self,
410         container: &str,
411     ) -> Result<Vec<FlagSnapshot>, AconfigdError> {
412         let storage_files = self
413             .get_storage_files(&container)
414             .ok_or(AconfigdError::FailToGetStorageFiles { container: container.to_string() })?;
415 
416         storage_files.list_all_flags()
417     }
418 
419     /// List all the flags
list_all_flags(&mut self) -> Result<Vec<FlagSnapshot>, AconfigdError>420     pub(crate) fn list_all_flags(&mut self) -> Result<Vec<FlagSnapshot>, AconfigdError> {
421         let mut flags = Vec::new();
422         for storage_files in self.all_storage_files.values_mut() {
423             if !storage_files.has_boot_copy() {
424                 continue;
425             }
426             flags.extend(storage_files.list_all_flags()?);
427         }
428         Ok(flags)
429     }
430 }
431 
432 #[cfg(test)]
433 mod tests {
434     use super::*;
435     use crate::storage_files::StorageRecord;
436     use crate::test_utils::{has_same_content, ContainerMock, StorageRootDirMock};
437     use crate::utils::{copy_file, get_files_digest, read_pb_from_file};
438     use aconfig_storage_file::{FlagValueSummary, StoredFlagType};
439     use aconfigd_protos::ProtoFlagOverride;
440 
441     #[test]
test_add_storage_files_from_pb()442     fn test_add_storage_files_from_pb() {
443         let root_dir = StorageRootDirMock::new();
444         let container = ContainerMock::new();
445 
446         let persist_package_map = root_dir.maps_dir.join("mockup.package.map");
447         let persist_flag_map = root_dir.maps_dir.join("mockup.flag.map");
448         let persist_flag_val = root_dir.flags_dir.join("mockup.val");
449         let persist_flag_info = root_dir.flags_dir.join("mockup.info");
450         copy_file(&container.package_map, &persist_package_map, 0o444).unwrap();
451         copy_file(&container.flag_map, &persist_flag_map, 0o444).unwrap();
452         copy_file(&container.flag_val, &persist_flag_val, 0o644).unwrap();
453         copy_file(&container.flag_info, &persist_flag_info, 0o644).unwrap();
454 
455         let mut pb = ProtoPersistStorageRecord::new();
456         pb.set_version(123);
457         pb.set_container("mockup".to_string());
458         pb.set_package_map(container.package_map.display().to_string());
459         pb.set_flag_map(container.flag_map.display().to_string());
460         pb.set_flag_val(container.flag_val.display().to_string());
461         pb.set_flag_info(container.flag_info.display().to_string());
462         pb.set_digest(String::from("abc"));
463 
464         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
465         manager.add_storage_files_from_pb(&pb);
466         assert_eq!(manager.all_storage_files.len(), 1);
467         assert_eq!(
468             manager.all_storage_files.get("mockup").unwrap(),
469             &StorageFiles::from_pb(&pb, &root_dir.tmp_dir.path()).unwrap(),
470         );
471     }
472 
init_storage(container: &ContainerMock, manager: &mut StorageFilesManager)473     fn init_storage(container: &ContainerMock, manager: &mut StorageFilesManager) {
474         manager
475             .add_or_update_container_storage_files(
476                 &container.name,
477                 &container.package_map,
478                 &container.flag_map,
479                 &container.flag_val,
480                 &container.flag_info,
481             )
482             .unwrap();
483     }
484 
485     #[test]
test_add_storage_files_from_container()486     fn test_add_storage_files_from_container() {
487         let container = ContainerMock::new();
488         let root_dir = StorageRootDirMock::new();
489         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
490         init_storage(&container, &mut manager);
491 
492         let storage_files = manager.get_storage_files(&container.name).unwrap();
493 
494         let expected_record = StorageRecord {
495             version: 1,
496             container: String::from("mockup"),
497             default_package_map: container.package_map.clone(),
498             default_flag_map: container.flag_map.clone(),
499             default_flag_val: container.flag_val.clone(),
500             default_flag_info: container.flag_info.clone(),
501             persist_package_map: root_dir.maps_dir.join("mockup.package.map"),
502             persist_flag_map: root_dir.maps_dir.join("mockup.flag.map"),
503             persist_flag_val: root_dir.flags_dir.join("mockup.val"),
504             persist_flag_info: root_dir.flags_dir.join("mockup.info"),
505             local_overrides: root_dir.flags_dir.join("mockup_local_overrides.pb"),
506             boot_flag_val: root_dir.boot_dir.join("mockup.val"),
507             boot_flag_info: root_dir.boot_dir.join("mockup.info"),
508             digest: get_files_digest(
509                 &[
510                     container.package_map.as_path(),
511                     container.flag_map.as_path(),
512                     container.flag_val.as_path(),
513                     container.flag_info.as_path(),
514                 ][..],
515             )
516             .unwrap(),
517         };
518 
519         let expected_storage_files = StorageFiles {
520             storage_record: expected_record,
521             package_map: None,
522             flag_map: None,
523             flag_val: None,
524             boot_flag_val: None,
525             boot_flag_info: None,
526             persist_flag_val: None,
527             persist_flag_info: None,
528             mutable_boot_flag_val: None,
529             mutable_boot_flag_info: None,
530         };
531 
532         assert_eq!(storage_files, &expected_storage_files);
533 
534         assert!(has_same_content(
535             &container.package_map,
536             &storage_files.storage_record.persist_package_map
537         ));
538         assert!(has_same_content(
539             &container.flag_map,
540             &storage_files.storage_record.persist_flag_map
541         ));
542         assert!(has_same_content(
543             &container.flag_val,
544             &storage_files.storage_record.persist_flag_val
545         ));
546         assert!(has_same_content(
547             &container.flag_info,
548             &storage_files.storage_record.persist_flag_info
549         ));
550         assert!(has_same_content(&container.flag_val, &storage_files.storage_record.boot_flag_val));
551         assert!(has_same_content(
552             &container.flag_info,
553             &storage_files.storage_record.boot_flag_info
554         ));
555     }
556 
557     #[test]
test_simple_update_container_storage_files()558     fn test_simple_update_container_storage_files() {
559         let container = ContainerMock::new();
560         let root_dir = StorageRootDirMock::new();
561         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
562         init_storage(&container, &mut manager);
563 
564         // copy files over to mimic a container update
565         std::fs::copy("./tests/data/container_with_more_flags.package.map", &container.package_map)
566             .unwrap();
567         std::fs::copy("./tests/data/container_with_more_flags.flag.map", &container.flag_map)
568             .unwrap();
569         std::fs::copy("./tests/data/container_with_more_flags.flag.val", &container.flag_val)
570             .unwrap();
571         std::fs::copy("./tests/data/container_with_more_flags.flag.info", &container.flag_info)
572             .unwrap();
573 
574         // update container
575         manager
576             .add_or_update_container_storage_files(
577                 &container.name,
578                 &container.package_map,
579                 &container.flag_map,
580                 &container.flag_val,
581                 &container.flag_info,
582             )
583             .unwrap();
584 
585         let storage_files = manager.get_storage_files(&container.name).unwrap();
586 
587         assert!(has_same_content(
588             &Path::new("./tests/data/container_with_more_flags.package.map"),
589             &storage_files.storage_record.persist_package_map
590         ));
591         assert!(has_same_content(
592             &Path::new("./tests/data/container_with_more_flags.flag.map"),
593             &storage_files.storage_record.persist_flag_map
594         ));
595         assert!(has_same_content(
596             &Path::new("./tests/data/container_with_more_flags.flag.val"),
597             &storage_files.storage_record.persist_flag_val
598         ));
599         assert!(has_same_content(
600             &Path::new("./tests/data/container_with_more_flags.flag.info"),
601             &storage_files.storage_record.persist_flag_info
602         ));
603         assert!(has_same_content(
604             &Path::new("./tests/data/container_with_more_flags.flag.val"),
605             &storage_files.storage_record.boot_flag_val
606         ));
607         assert!(has_same_content(
608             &Path::new("./tests/data/container_with_more_flags.flag.info"),
609             &storage_files.storage_record.boot_flag_info
610         ));
611         assert!(storage_files.storage_record.local_overrides.exists());
612     }
613 
add_example_overrides(manager: &mut StorageFilesManager)614     fn add_example_overrides(manager: &mut StorageFilesManager) {
615         manager
616             .override_flag_value(
617                 "com.android.aconfig.storage.test_1",
618                 "enabled_rw",
619                 "false",
620                 ProtoFlagOverrideType::SERVER_ON_REBOOT,
621             )
622             .unwrap();
623 
624         manager
625             .override_flag_value(
626                 "com.android.aconfig.storage.test_1",
627                 "disabled_rw",
628                 "false",
629                 ProtoFlagOverrideType::SERVER_ON_REBOOT,
630             )
631             .unwrap();
632 
633         manager
634             .override_flag_value(
635                 "com.android.aconfig.storage.test_1",
636                 "disabled_rw",
637                 "true",
638                 ProtoFlagOverrideType::LOCAL_ON_REBOOT,
639             )
640             .unwrap();
641     }
642 
643     #[test]
test_overrides_after_update_container_storage_files()644     fn test_overrides_after_update_container_storage_files() {
645         let container = ContainerMock::new();
646         let root_dir = StorageRootDirMock::new();
647         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
648         init_storage(&container, &mut manager);
649         add_example_overrides(&mut manager);
650 
651         // copy files over to mimic a container update
652         std::fs::copy("./tests/data/package.map", &container.package_map).unwrap();
653         std::fs::copy("./tests/data/flag.map", &container.flag_map).unwrap();
654         std::fs::copy("./tests/data/flag.val", &container.flag_val).unwrap();
655         std::fs::copy("./tests/data/flag.info", &container.flag_info).unwrap();
656 
657         // update container
658         manager
659             .add_or_update_container_storage_files(
660                 &container.name,
661                 &container.package_map,
662                 &container.flag_map,
663                 &container.flag_val,
664                 &container.flag_info,
665             )
666             .unwrap();
667 
668         // verify that server override is persisted
669         let storage_files = manager.get_storage_files(&container.name).unwrap();
670         let server_overrides = storage_files.get_all_server_overrides().unwrap();
671         assert_eq!(server_overrides.len(), 2);
672         assert_eq!(
673             server_overrides[0],
674             FlagValueSummary {
675                 package_name: "com.android.aconfig.storage.test_1".to_string(),
676                 flag_name: "disabled_rw".to_string(),
677                 flag_value: "false".to_string(),
678                 value_type: StoredFlagType::ReadWriteBoolean,
679             }
680         );
681         assert_eq!(
682             server_overrides[1],
683             FlagValueSummary {
684                 package_name: "com.android.aconfig.storage.test_1".to_string(),
685                 flag_name: "enabled_rw".to_string(),
686                 flag_value: "false".to_string(),
687                 value_type: StoredFlagType::ReadWriteBoolean,
688             }
689         );
690 
691         // verify that local override is persisted
692         let local_overrides = storage_files.get_all_local_overrides().unwrap();
693         assert_eq!(local_overrides.len(), 1);
694         let mut pb = ProtoFlagOverride::new();
695         pb.set_package_name("com.android.aconfig.storage.test_1".to_string());
696         pb.set_flag_name("disabled_rw".to_string());
697         pb.set_flag_value("true".to_string());
698         assert_eq!(local_overrides[0], pb);
699     }
700 
701     #[test]
test_apply_all_staged_overrides()702     fn test_apply_all_staged_overrides() {
703         let container = ContainerMock::new();
704         let root_dir = StorageRootDirMock::new();
705         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
706         init_storage(&container, &mut manager);
707         add_example_overrides(&mut manager);
708         manager.apply_all_staged_overrides("mockup").unwrap();
709 
710         let mut flag =
711             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "enabled_rw").unwrap();
712 
713         let mut expected_flag = FlagSnapshot {
714             container: String::from("mockup"),
715             package: String::from("com.android.aconfig.storage.test_1"),
716             flag: String::from("enabled_rw"),
717             server_value: String::from("false"),
718             local_value: String::new(),
719             boot_value: String::from("false"),
720             default_value: String::from("true"),
721             is_readwrite: true,
722             has_server_override: true,
723             has_local_override: false,
724         };
725 
726         assert_eq!(flag, Some(expected_flag));
727 
728         flag =
729             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "disabled_rw").unwrap();
730 
731         expected_flag = FlagSnapshot {
732             container: String::from("mockup"),
733             package: String::from("com.android.aconfig.storage.test_1"),
734             flag: String::from("disabled_rw"),
735             server_value: String::from("false"),
736             local_value: String::from("true"),
737             boot_value: String::from("true"),
738             default_value: String::from("false"),
739             is_readwrite: true,
740             has_server_override: true,
741             has_local_override: true,
742         };
743 
744         assert_eq!(flag, Some(expected_flag));
745     }
746 
747     #[test]
test_reset_all_storage()748     fn test_reset_all_storage() {
749         let container = ContainerMock::new();
750         let root_dir = StorageRootDirMock::new();
751         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
752         init_storage(&container, &mut manager);
753         add_example_overrides(&mut manager);
754         manager.apply_all_staged_overrides("mockup").unwrap();
755 
756         manager.reset_all_storage().unwrap();
757         let storage_files = manager.get_storage_files(&container.name).unwrap();
758         assert!(has_same_content(
759             &container.flag_val,
760             &storage_files.storage_record.persist_flag_val
761         ));
762         assert!(has_same_content(
763             &container.flag_info,
764             &storage_files.storage_record.persist_flag_info
765         ));
766         assert!(has_same_content(&container.flag_val, &storage_files.storage_record.boot_flag_val));
767         assert!(has_same_content(
768             &container.flag_info,
769             &storage_files.storage_record.boot_flag_info
770         ));
771     }
772 
test_override_flag_server_on_reboot()773     fn test_override_flag_server_on_reboot() {
774         let container = ContainerMock::new();
775         let root_dir = StorageRootDirMock::new();
776         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
777         init_storage(&container, &mut manager);
778         manager.apply_all_staged_overrides("mockup").unwrap();
779 
780         manager
781             .override_flag_value(
782                 "com.android.aconfig.storage.test_1",
783                 "enabled_rw",
784                 "false",
785                 ProtoFlagOverrideType::SERVER_ON_REBOOT,
786             )
787             .unwrap();
788 
789         let flag =
790             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "enabled_rw").unwrap();
791 
792         let expected_flag = FlagSnapshot {
793             container: String::from("mockup"),
794             package: String::from("com.android.aconfig.storage.test_1"),
795             flag: String::from("enabled_rw"),
796             server_value: String::from("false"),
797             local_value: String::new(),
798             boot_value: String::from("true"),
799             default_value: String::from("true"),
800             is_readwrite: true,
801             has_server_override: true,
802             has_local_override: false,
803         };
804 
805         assert_eq!(flag, Some(expected_flag));
806     }
807 
808     #[test]
test_override_flag_local_on_reboot()809     fn test_override_flag_local_on_reboot() {
810         let container = ContainerMock::new();
811         let root_dir = StorageRootDirMock::new();
812         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
813         init_storage(&container, &mut manager);
814         manager.apply_all_staged_overrides("mockup").unwrap();
815 
816         manager
817             .override_flag_value(
818                 "com.android.aconfig.storage.test_1",
819                 "enabled_rw",
820                 "false",
821                 ProtoFlagOverrideType::LOCAL_ON_REBOOT,
822             )
823             .unwrap();
824 
825         let flag =
826             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "enabled_rw").unwrap();
827 
828         let expected_flag = FlagSnapshot {
829             container: String::from("mockup"),
830             package: String::from("com.android.aconfig.storage.test_1"),
831             flag: String::from("enabled_rw"),
832             server_value: String::new(),
833             local_value: String::from("false"),
834             boot_value: String::from("true"),
835             default_value: String::from("true"),
836             is_readwrite: true,
837             has_server_override: false,
838             has_local_override: true,
839         };
840 
841         assert_eq!(flag, Some(expected_flag));
842     }
843 
844     #[test]
test_override_flag_local_immediate()845     fn test_override_flag_local_immediate() {
846         let container = ContainerMock::new();
847         let root_dir = StorageRootDirMock::new();
848         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
849         init_storage(&container, &mut manager);
850         manager.apply_all_staged_overrides("mockup").unwrap();
851 
852         manager
853             .override_flag_value(
854                 "com.android.aconfig.storage.test_1",
855                 "enabled_rw",
856                 "false",
857                 ProtoFlagOverrideType::LOCAL_IMMEDIATE,
858             )
859             .unwrap();
860 
861         let flag =
862             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "enabled_rw").unwrap();
863 
864         let expected_flag = FlagSnapshot {
865             container: String::from("mockup"),
866             package: String::from("com.android.aconfig.storage.test_1"),
867             flag: String::from("enabled_rw"),
868             server_value: String::new(),
869             local_value: String::from("false"),
870             boot_value: String::from("false"),
871             default_value: String::from("true"),
872             is_readwrite: true,
873             has_server_override: false,
874             has_local_override: true,
875         };
876 
877         assert_eq!(flag, Some(expected_flag));
878     }
879 
880     #[test]
test_get_ota_flags()881     fn test_get_ota_flags() {
882         let root_dir = StorageRootDirMock::new();
883         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
884 
885         let mut ota_flags = ProtoOTAFlagStagingMessage::new();
886         ota_flags.set_build_id("xyz.123".to_string());
887         write_pb_to_file::<ProtoOTAFlagStagingMessage>(
888             &ota_flags,
889             &root_dir.flags_dir.join("ota.pb"),
890         )
891         .unwrap();
892         let staged_ota_flags = manager.get_ota_flags().unwrap();
893         assert!(staged_ota_flags.is_none());
894         assert!(root_dir.flags_dir.join("ota.pb").exists());
895 
896         let device_build_id =
897             rustutils::system_properties::read("ro.build.fingerprint").unwrap().unwrap();
898         ota_flags.set_build_id(device_build_id);
899         let mut flag1 = ProtoFlagOverride::new();
900         flag1.set_package_name("com.android.aconfig.storage.test_1".to_string());
901         flag1.set_flag_name("enabled_rw".to_string());
902         flag1.set_flag_value("false".to_string());
903         ota_flags.overrides.push(flag1.clone());
904         let mut flag2 = ProtoFlagOverride::new();
905         flag2.set_package_name("com.android.aconfig.storage.test_2".to_string());
906         flag2.set_flag_name("disabled_rw".to_string());
907         flag2.set_flag_value("true".to_string());
908         ota_flags.overrides.push(flag2.clone());
909         write_pb_to_file::<ProtoOTAFlagStagingMessage>(
910             &ota_flags,
911             &root_dir.flags_dir.join("ota.pb"),
912         )
913         .unwrap();
914         let staged_ota_flags = manager.get_ota_flags().unwrap().unwrap();
915         assert_eq!(staged_ota_flags.len(), 2);
916         assert_eq!(staged_ota_flags[0], flag1);
917         assert_eq!(staged_ota_flags[1], flag2);
918         assert!(!root_dir.flags_dir.join("ota.pb").exists());
919     }
920 
921     #[test]
test_apply_staged_ota_flags()922     fn test_apply_staged_ota_flags() {
923         let container = ContainerMock::new();
924         let root_dir = StorageRootDirMock::new();
925         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
926         init_storage(&container, &mut manager);
927 
928         let mut ota_flags = ProtoOTAFlagStagingMessage::new();
929         let device_build_id =
930             rustutils::system_properties::read("ro.build.fingerprint").unwrap().unwrap();
931         ota_flags.set_build_id(device_build_id);
932         let mut flag1 = ProtoFlagOverride::new();
933         flag1.set_package_name("com.android.aconfig.storage.test_1".to_string());
934         flag1.set_flag_name("enabled_rw".to_string());
935         flag1.set_flag_value("false".to_string());
936         ota_flags.overrides.push(flag1.clone());
937         let mut flag2 = ProtoFlagOverride::new();
938         flag2.set_package_name("com.android.aconfig.storage.test_2".to_string());
939         flag2.set_flag_name("disabled_rw".to_string());
940         flag2.set_flag_value("true".to_string());
941         ota_flags.overrides.push(flag2.clone());
942         let mut flag3 = ProtoFlagOverride::new();
943         flag3.set_package_name("not_exist".to_string());
944         flag3.set_flag_name("not_exist".to_string());
945         flag3.set_flag_value("true".to_string());
946         ota_flags.overrides.push(flag3.clone());
947         write_pb_to_file::<ProtoOTAFlagStagingMessage>(
948             &ota_flags,
949             &root_dir.flags_dir.join("ota.pb"),
950         )
951         .unwrap();
952 
953         manager.apply_staged_ota_flags().unwrap();
954         let storage_files = manager.get_storage_files(&container.name).unwrap();
955         let server_overrides = storage_files.get_all_server_overrides().unwrap();
956         assert_eq!(server_overrides.len(), 2);
957         assert_eq!(
958             server_overrides[0].package_name,
959             "com.android.aconfig.storage.test_1".to_string()
960         );
961         assert_eq!(server_overrides[0].flag_name, "enabled_rw".to_string());
962         assert_eq!(server_overrides[0].flag_value, "false".to_string());
963         assert_eq!(
964             server_overrides[1].package_name,
965             "com.android.aconfig.storage.test_2".to_string()
966         );
967         assert_eq!(server_overrides[1].flag_name, "disabled_rw".to_string());
968         assert_eq!(server_overrides[1].flag_value, "true".to_string());
969     }
970 
971     #[test]
test_write_persist_storage_records_to_file()972     fn test_write_persist_storage_records_to_file() {
973         let container = ContainerMock::new();
974         let root_dir = StorageRootDirMock::new();
975         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
976         init_storage(&container, &mut manager);
977 
978         let pb_file = root_dir.tmp_dir.path().join("records.pb");
979         manager.write_persist_storage_records_to_file(&pb_file).unwrap();
980 
981         let pb = read_pb_from_file::<ProtoPersistStorageRecords>(&pb_file).unwrap();
982         assert_eq!(pb.records.len(), 1);
983 
984         let mut entry = ProtoPersistStorageRecord::new();
985         entry.set_version(1);
986         entry.set_container("mockup".to_string());
987         entry.set_package_map(container.package_map.display().to_string());
988         entry.set_flag_map(container.flag_map.display().to_string());
989         entry.set_flag_val(container.flag_val.display().to_string());
990         entry.set_flag_info(container.flag_info.display().to_string());
991         let digest = get_files_digest(
992             &[
993                 container.package_map.as_path(),
994                 container.flag_map.as_path(),
995                 container.flag_val.as_path(),
996                 container.flag_info.as_path(),
997             ][..],
998         )
999         .unwrap();
1000         entry.set_digest(digest);
1001         assert_eq!(pb.records[0], entry);
1002     }
1003 
1004     #[test]
test_remove_local_override()1005     fn test_remove_local_override() {
1006         let container = ContainerMock::new();
1007         let root_dir = StorageRootDirMock::new();
1008         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
1009         init_storage(&container, &mut manager);
1010         add_example_overrides(&mut manager);
1011         manager.apply_all_staged_overrides("mockup").unwrap();
1012 
1013         manager.remove_local_override("com.android.aconfig.storage.test_1", "disabled_rw").unwrap();
1014 
1015         let flag =
1016             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "disabled_rw").unwrap();
1017 
1018         let expected_flag = FlagSnapshot {
1019             container: String::from("mockup"),
1020             package: String::from("com.android.aconfig.storage.test_1"),
1021             flag: String::from("disabled_rw"),
1022             server_value: String::from("false"),
1023             local_value: String::new(),
1024             boot_value: String::from("true"),
1025             default_value: String::from("false"),
1026             is_readwrite: true,
1027             has_server_override: true,
1028             has_local_override: false,
1029         };
1030 
1031         assert_eq!(flag, Some(expected_flag));
1032     }
1033 
1034     #[test]
test_remove_all_local_override()1035     fn test_remove_all_local_override() {
1036         let container = ContainerMock::new();
1037         let root_dir = StorageRootDirMock::new();
1038         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
1039         init_storage(&container, &mut manager);
1040 
1041         manager
1042             .override_flag_value(
1043                 "com.android.aconfig.storage.test_1",
1044                 "disabled_rw",
1045                 "true",
1046                 ProtoFlagOverrideType::LOCAL_ON_REBOOT,
1047             )
1048             .unwrap();
1049 
1050         manager
1051             .override_flag_value(
1052                 "com.android.aconfig.storage.test_2",
1053                 "disabled_rw",
1054                 "true",
1055                 ProtoFlagOverrideType::LOCAL_ON_REBOOT,
1056             )
1057             .unwrap();
1058         manager.apply_all_staged_overrides("mockup").unwrap();
1059         manager.remove_all_local_overrides().unwrap();
1060 
1061         let mut flag =
1062             manager.get_flag_snapshot("com.android.aconfig.storage.test_1", "disabled_rw").unwrap();
1063 
1064         let mut expected_flag = FlagSnapshot {
1065             container: String::from("mockup"),
1066             package: String::from("com.android.aconfig.storage.test_1"),
1067             flag: String::from("disabled_rw"),
1068             server_value: String::from(""),
1069             local_value: String::new(),
1070             boot_value: String::from("true"),
1071             default_value: String::from("false"),
1072             is_readwrite: true,
1073             has_server_override: false,
1074             has_local_override: false,
1075         };
1076 
1077         assert_eq!(flag, Some(expected_flag));
1078 
1079         flag =
1080             manager.get_flag_snapshot("com.android.aconfig.storage.test_2", "disabled_rw").unwrap();
1081 
1082         expected_flag = FlagSnapshot {
1083             container: String::from("mockup"),
1084             package: String::from("com.android.aconfig.storage.test_2"),
1085             flag: String::from("disabled_rw"),
1086             server_value: String::from(""),
1087             local_value: String::new(),
1088             boot_value: String::from("true"),
1089             default_value: String::from("false"),
1090             is_readwrite: true,
1091             has_server_override: false,
1092             has_local_override: false,
1093         };
1094 
1095         assert_eq!(flag, Some(expected_flag));
1096     }
1097 
1098     #[test]
test_list_flags_in_package()1099     fn test_list_flags_in_package() {
1100         let container = ContainerMock::new();
1101         let root_dir = StorageRootDirMock::new();
1102         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
1103         init_storage(&container, &mut manager);
1104         add_example_overrides(&mut manager);
1105         manager.apply_all_staged_overrides("mockup").unwrap();
1106 
1107         let flags = manager.list_flags_in_package("com.android.aconfig.storage.test_1").unwrap();
1108 
1109         let mut flag = FlagSnapshot {
1110             container: String::from("mockup"),
1111             package: String::from("com.android.aconfig.storage.test_1"),
1112             flag: String::from("disabled_rw"),
1113             server_value: String::from("false"),
1114             local_value: String::from("true"),
1115             boot_value: String::from("true"),
1116             default_value: String::from("false"),
1117             is_readwrite: true,
1118             has_server_override: true,
1119             has_local_override: true,
1120         };
1121         assert_eq!(flags[0], flag);
1122 
1123         flag = FlagSnapshot {
1124             container: String::from("mockup"),
1125             package: String::from("com.android.aconfig.storage.test_1"),
1126             flag: String::from("enabled_ro"),
1127             server_value: String::new(),
1128             local_value: String::new(),
1129             boot_value: String::from("true"),
1130             default_value: String::from("true"),
1131             is_readwrite: false,
1132             has_server_override: false,
1133             has_local_override: false,
1134         };
1135         assert_eq!(flags[1], flag);
1136 
1137         flag = FlagSnapshot {
1138             container: String::from("mockup"),
1139             package: String::from("com.android.aconfig.storage.test_1"),
1140             flag: String::from("enabled_rw"),
1141             server_value: String::from("false"),
1142             local_value: String::new(),
1143             boot_value: String::from("false"),
1144             default_value: String::from("true"),
1145             is_readwrite: true,
1146             has_server_override: true,
1147             has_local_override: false,
1148         };
1149         assert_eq!(flags[2], flag);
1150     }
1151 
1152     #[test]
test_list_flags_in_container()1153     fn test_list_flags_in_container() {
1154         let container = ContainerMock::new();
1155         let root_dir = StorageRootDirMock::new();
1156         let mut manager = StorageFilesManager::new(&root_dir.tmp_dir.path());
1157         init_storage(&container, &mut manager);
1158         add_example_overrides(&mut manager);
1159         manager.apply_all_staged_overrides("mockup").unwrap();
1160 
1161         let flags = manager.list_flags_in_container("mockup").unwrap();
1162         assert_eq!(flags.len(), 8);
1163 
1164         let mut flag = FlagSnapshot {
1165             container: String::from("mockup"),
1166             package: String::from("com.android.aconfig.storage.test_1"),
1167             flag: String::from("enabled_rw"),
1168             server_value: String::from("false"),
1169             local_value: String::new(),
1170             boot_value: String::from("false"),
1171             default_value: String::from("true"),
1172             is_readwrite: true,
1173             has_server_override: true,
1174             has_local_override: false,
1175         };
1176         assert_eq!(flags[2], flag);
1177 
1178         flag = FlagSnapshot {
1179             container: String::from("mockup"),
1180             package: String::from("com.android.aconfig.storage.test_1"),
1181             flag: String::from("disabled_rw"),
1182             server_value: String::from("false"),
1183             local_value: String::from("true"),
1184             boot_value: String::from("true"),
1185             default_value: String::from("false"),
1186             is_readwrite: true,
1187             has_server_override: true,
1188             has_local_override: true,
1189         };
1190         assert_eq!(flags[0], flag);
1191     }
1192 }
1193