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::utils::{copy_file, get_files_digest, read_pb_from_file, remove_file, write_pb_to_file};
18 use crate::AconfigdError;
19 use aconfig_storage_file::{
20     list_flags, list_flags_with_info, FlagInfoBit, FlagValueSummary, FlagValueType,
21 };
22 use aconfig_storage_read_api::{
23     get_boolean_flag_value, get_flag_read_context, get_package_read_context,
24     get_storage_file_version, map_file,
25 };
26 use aconfig_storage_write_api::{
27     map_mutable_storage_file, set_boolean_flag_value, set_flag_has_local_override,
28     set_flag_has_server_override,
29 };
30 use aconfigd_protos::{ProtoFlagOverride, ProtoLocalFlagOverrides, ProtoPersistStorageRecord};
31 use anyhow::anyhow;
32 use memmap2::{Mmap, MmapMut};
33 use std::collections::HashMap;
34 use std::path::{Path, PathBuf};
35 
36 // In memory data structure for storage file locations for each container
37 #[derive(PartialEq, Debug, Clone)]
38 pub(crate) struct StorageRecord {
39     pub version: u32,
40     pub container: String,            // container name
41     pub default_package_map: PathBuf, // default package map file
42     pub default_flag_map: PathBuf,    // default flag map file
43     pub default_flag_val: PathBuf,    // default flag val file
44     pub default_flag_info: PathBuf,   // default flag info file
45     pub persist_package_map: PathBuf, // persist package.map file
46     pub persist_flag_map: PathBuf,    // persist flag.map file
47     pub persist_flag_val: PathBuf,    // persist flag.val file
48     pub persist_flag_info: PathBuf,   // persist flag.info file
49     pub local_overrides: PathBuf,     // local overrides pb file
50     pub boot_flag_val: PathBuf,       // boot flag.val file
51     pub boot_flag_info: PathBuf,      // boot flag.info file
52     pub digest: String,               // hash for all default storage files
53 }
54 
55 // Storage files for a particular container
56 #[derive(Debug)]
57 pub(crate) struct StorageFiles {
58     pub storage_record: StorageRecord,
59     pub package_map: Option<Mmap>,
60     pub flag_map: Option<Mmap>,
61     pub flag_val: Option<Mmap>,                  // default flag value file
62     pub boot_flag_val: Option<Mmap>,             // boot flag value file
63     pub boot_flag_info: Option<Mmap>,            // boot flag info file
64     pub persist_flag_val: Option<MmapMut>,       // persist flag value file
65     pub persist_flag_info: Option<MmapMut>,      // persist flag info file
66     pub mutable_boot_flag_val: Option<MmapMut>,  // mutable boot flag value file
67     pub mutable_boot_flag_info: Option<MmapMut>, // mutable boot flag info file
68 }
69 
70 // Compare two options of mmap/mmapmut
same_mmap_contents<T: std::ops::Deref<Target = [u8]>>( opt_a: &Option<T>, opt_b: &Option<T>, ) -> bool71 fn same_mmap_contents<T: std::ops::Deref<Target = [u8]>>(
72     opt_a: &Option<T>,
73     opt_b: &Option<T>,
74 ) -> bool {
75     match (opt_a, opt_b) {
76         (Some(map_a), Some(map_b)) => map_a[..] == map_b[..],
77         (None, None) => true,
78         _ => false,
79     }
80 }
81 
82 impl PartialEq for StorageFiles {
eq(&self, other: &Self) -> bool83     fn eq(&self, other: &Self) -> bool {
84         self.storage_record == other.storage_record
85             && same_mmap_contents(&self.package_map, &other.package_map)
86             && same_mmap_contents(&self.flag_map, &other.flag_map)
87             && same_mmap_contents(&self.flag_val, &other.flag_val)
88             && same_mmap_contents(&self.boot_flag_val, &other.boot_flag_val)
89             && same_mmap_contents(&self.boot_flag_info, &other.boot_flag_info)
90             && same_mmap_contents(&self.persist_flag_val, &other.persist_flag_val)
91             && same_mmap_contents(&self.persist_flag_info, &other.persist_flag_info)
92             && same_mmap_contents(&self.mutable_boot_flag_val, &other.mutable_boot_flag_val)
93             && same_mmap_contents(&self.mutable_boot_flag_info, &other.mutable_boot_flag_info)
94     }
95 }
96 
97 // Package and flag query context
98 #[derive(PartialEq, Debug)]
99 pub(crate) struct PackageFlagContext {
100     pub package: String,
101     pub flag: String,
102     pub package_exists: bool,
103     pub flag_exists: bool,
104     pub value_type: FlagValueType,
105     pub flag_index: u32,
106 }
107 
108 // Flag snapshot in storage
109 #[derive(PartialEq, Debug)]
110 pub(crate) struct FlagSnapshot {
111     pub container: String,
112     pub package: String,
113     pub flag: String,
114     pub server_value: String,
115     pub local_value: String,
116     pub boot_value: String,
117     pub default_value: String,
118     pub is_readwrite: bool,
119     pub has_server_override: bool,
120     pub has_local_override: bool,
121 }
122 
123 impl StorageFiles {
124     /// Constructor from a container
from_container( container: &str, package_map: &Path, flag_map: &Path, flag_val: &Path, flag_info: &Path, root_dir: &Path, ) -> Result<Self, AconfigdError>125     pub(crate) fn from_container(
126         container: &str,
127         package_map: &Path,
128         flag_map: &Path,
129         flag_val: &Path,
130         flag_info: &Path,
131         root_dir: &Path,
132     ) -> Result<Self, AconfigdError> {
133         let version =
134             get_storage_file_version(&flag_val.display().to_string()).map_err(|errmsg| {
135                 AconfigdError::FailToGetFileVersion { file: flag_val.display().to_string(), errmsg }
136             })?;
137 
138         let record = StorageRecord {
139             version,
140             container: container.to_string(),
141             default_package_map: package_map.to_path_buf(),
142             default_flag_map: flag_map.to_path_buf(),
143             default_flag_val: flag_val.to_path_buf(),
144             default_flag_info: flag_info.to_path_buf(),
145             persist_package_map: root_dir.join("maps").join(container.to_string() + ".package.map"),
146             persist_flag_map: root_dir.join("maps").join(container.to_string() + ".flag.map"),
147             persist_flag_val: root_dir.join("flags").join(container.to_string() + ".val"),
148             persist_flag_info: root_dir.join("flags").join(container.to_string() + ".info"),
149             local_overrides: root_dir
150                 .join("flags")
151                 .join(container.to_string() + "_local_overrides.pb"),
152             boot_flag_val: root_dir.join("boot").join(container.to_string() + ".val"),
153             boot_flag_info: root_dir.join("boot").join(container.to_string() + ".info"),
154             digest: get_files_digest(&[package_map, flag_map, flag_val, flag_info][..])?,
155         };
156 
157         copy_file(package_map, &record.persist_package_map, 0o444)?;
158         copy_file(flag_map, &record.persist_flag_map, 0o444)?;
159         copy_file(flag_val, &record.persist_flag_val, 0o644)?;
160         copy_file(flag_info, &record.persist_flag_info, 0o644)?;
161         copy_file(flag_val, &record.boot_flag_val, 0o644)?;
162         copy_file(flag_info, &record.boot_flag_info, 0o644)?;
163 
164         let pb = ProtoLocalFlagOverrides::new();
165         write_pb_to_file::<ProtoLocalFlagOverrides>(&pb, &record.local_overrides)?;
166 
167         let files = Self {
168             storage_record: record,
169             package_map: None,
170             flag_map: None,
171             flag_val: None,
172             boot_flag_val: None,
173             boot_flag_info: None,
174             persist_flag_val: None,
175             persist_flag_info: None,
176             mutable_boot_flag_val: None,
177             mutable_boot_flag_info: None,
178         };
179 
180         Ok(files)
181     }
182 
has_boot_copy(&self) -> bool183     pub(crate) fn has_boot_copy(&self) -> bool {
184         self.storage_record.boot_flag_val.exists() && self.storage_record.boot_flag_info.exists()
185     }
186 
187     /// Constructor from a pb record
from_pb( pb: &ProtoPersistStorageRecord, root_dir: &Path, ) -> Result<Self, AconfigdError>188     pub(crate) fn from_pb(
189         pb: &ProtoPersistStorageRecord,
190         root_dir: &Path,
191     ) -> Result<Self, AconfigdError> {
192         let record = StorageRecord {
193             version: pb.version(),
194             container: pb.container().to_string(),
195             default_package_map: PathBuf::from(pb.package_map()),
196             default_flag_map: PathBuf::from(pb.flag_map()),
197             default_flag_val: PathBuf::from(pb.flag_val()),
198             default_flag_info: PathBuf::from(pb.flag_info()),
199             persist_package_map: root_dir
200                 .join("maps")
201                 .join(pb.container().to_string() + ".package.map"),
202             persist_flag_map: root_dir.join("maps").join(pb.container().to_string() + ".flag.map"),
203             persist_flag_val: root_dir.join("flags").join(pb.container().to_string() + ".val"),
204             persist_flag_info: root_dir.join("flags").join(pb.container().to_string() + ".info"),
205             local_overrides: root_dir
206                 .join("flags")
207                 .join(pb.container().to_string() + "_local_overrides.pb"),
208             boot_flag_val: root_dir.join("boot").join(pb.container().to_string() + ".val"),
209             boot_flag_info: root_dir.join("boot").join(pb.container().to_string() + ".info"),
210             digest: pb.digest().to_string(),
211         };
212 
213         copy_file(&record.persist_flag_val, &record.boot_flag_val, 0o644)?;
214         copy_file(&record.persist_flag_info, &record.boot_flag_info, 0o644)?;
215 
216         Ok(Self {
217             storage_record: record,
218             package_map: None,
219             flag_map: None,
220             flag_val: None,
221             boot_flag_val: None,
222             boot_flag_info: None,
223             persist_flag_val: None,
224             persist_flag_info: None,
225             mutable_boot_flag_val: None,
226             mutable_boot_flag_info: None,
227         })
228     }
229 
230     /// Get immutable file mapping of a file.
231     ///
232     /// # Safety
233     ///
234     /// The memory mapped file may have undefined behavior if there are writes to the underlying
235     /// file after being mapped. Ensure no writes can happen to the underlying file that is memory
236     /// mapped while this mapping stays alive to guarantee safety.
get_immutable_file_mapping(file_path: &Path) -> Result<Mmap, AconfigdError>237     unsafe fn get_immutable_file_mapping(file_path: &Path) -> Result<Mmap, AconfigdError> {
238         // SAFETY: As per the safety comment, there are no other writes to the underlying file.
239         unsafe {
240             map_file(&file_path.display().to_string()).map_err(|errmsg| {
241                 AconfigdError::FailToMapFile { file: file_path.display().to_string(), errmsg }
242             })
243         }
244     }
245 
246     /// Get package map memory mapping.
get_package_map(&mut self) -> Result<&Mmap, AconfigdError>247     fn get_package_map(&mut self) -> Result<&Mmap, AconfigdError> {
248         if self.package_map.is_none() {
249             // SAFETY: Here it is safe as package map files are always read only.
250             self.package_map = unsafe {
251                 Some(Self::get_immutable_file_mapping(&self.storage_record.persist_package_map)?)
252             };
253         }
254         Ok(self.package_map.as_ref().unwrap())
255     }
256 
257     /// Get flag map memory mapping.
get_flag_map(&mut self) -> Result<&Mmap, AconfigdError>258     fn get_flag_map(&mut self) -> Result<&Mmap, AconfigdError> {
259         if self.flag_map.is_none() {
260             // SAFETY: Here it is safe as flag map files are always read only.
261             self.flag_map = unsafe {
262                 Some(Self::get_immutable_file_mapping(&self.storage_record.persist_flag_map)?)
263             };
264         }
265         Ok(self.flag_map.as_ref().unwrap())
266     }
267 
268     /// Get default flag value memory mapping.
get_flag_val(&mut self) -> Result<&Mmap, AconfigdError>269     fn get_flag_val(&mut self) -> Result<&Mmap, AconfigdError> {
270         if self.flag_val.is_none() {
271             // SAFETY: Here it is safe as default flag value files are always read only.
272             self.flag_val = unsafe {
273                 Some(Self::get_immutable_file_mapping(&self.storage_record.default_flag_val)?)
274             };
275         }
276         Ok(self.flag_val.as_ref().unwrap())
277     }
278 
279     /// Get boot flag value memory mapping.
280     ///
281     /// # Safety
282     ///
283     /// The memory mapped file may have undefined behavior if there are writes to the underlying
284     /// file after being mapped. Ensure no writes can happen to the underlying file that is memory
285     /// mapped while this mapping stays alive to guarantee safety.
get_boot_flag_val(&mut self) -> Result<&Mmap, AconfigdError>286     unsafe fn get_boot_flag_val(&mut self) -> Result<&Mmap, AconfigdError> {
287         if self.boot_flag_val.is_none() {
288             // SAFETY: As per the safety comment, there are no other writes to the underlying file.
289             self.boot_flag_val = unsafe {
290                 Some(Self::get_immutable_file_mapping(&self.storage_record.boot_flag_val)?)
291             };
292         }
293         Ok(self.boot_flag_val.as_ref().unwrap())
294     }
295 
296     /// Get boot flag info memory mapping.
297     ///
298     /// # Safety
299     ///
300     /// The memory mapped file may have undefined behavior if there are writes to the underlying
301     /// file after being mapped. Ensure no writes can happen to the underlying file that is memory
302     /// mapped while this mapping stays alive to guarantee safety.
get_boot_flag_info(&mut self) -> Result<&Mmap, AconfigdError>303     unsafe fn get_boot_flag_info(&mut self) -> Result<&Mmap, AconfigdError> {
304         if self.boot_flag_info.is_none() {
305             // SAFETY: As per the safety comment, there are no other writes to the underlying file.
306             self.boot_flag_info = unsafe {
307                 Some(Self::get_immutable_file_mapping(&self.storage_record.boot_flag_info)?)
308             };
309         }
310         Ok(self.boot_flag_info.as_ref().unwrap())
311     }
312 
313     /// Get mutable file mapping of a file.
314     ///
315     /// # Safety
316     ///
317     /// The memory mapped file may have undefined behavior if there are writes to this
318     /// file not thru this memory mapped file or there are concurrent writes to this
319     /// memory mapped file. Ensure all writes to the underlying file are thru this memory
320     /// mapped file and there are no concurrent writes.
get_mutable_file_mapping( file_path: &Path, ) -> Result<MmapMut, AconfigdError>321     pub(crate) unsafe fn get_mutable_file_mapping(
322         file_path: &Path,
323     ) -> Result<MmapMut, AconfigdError> {
324         // SAFETY: As per the safety comment, there are no other writes to the underlying file.
325         unsafe {
326             map_mutable_storage_file(&file_path.display().to_string()).map_err(|errmsg| {
327                 AconfigdError::FailToMapFile { file: file_path.display().to_string(), errmsg }
328             })
329         }
330     }
331 
332     /// Get persist flag value memory mapping.
get_persist_flag_val(&mut self) -> Result<&mut MmapMut, AconfigdError>333     fn get_persist_flag_val(&mut self) -> Result<&mut MmapMut, AconfigdError> {
334         if self.persist_flag_val.is_none() {
335             // SAFETY: safety is ensured that all writes to the persist file is thru this
336             // memory mapping, and there are no concurrent writes
337             self.persist_flag_val = unsafe {
338                 Some(Self::get_mutable_file_mapping(&self.storage_record.persist_flag_val)?)
339             };
340         }
341         Ok(self.persist_flag_val.as_mut().unwrap())
342     }
343 
344     /// Get persist flag info memory mapping.
get_persist_flag_info(&mut self) -> Result<&mut MmapMut, AconfigdError>345     fn get_persist_flag_info(&mut self) -> Result<&mut MmapMut, AconfigdError> {
346         if self.persist_flag_info.is_none() {
347             // SAFETY: safety is ensured that all writes to the persist file is thru this
348             // memory mapping, and there are no concurrent writes
349             self.persist_flag_info = unsafe {
350                 Some(Self::get_mutable_file_mapping(&self.storage_record.persist_flag_info)?)
351             };
352         }
353         Ok(self.persist_flag_info.as_mut().unwrap())
354     }
355 
356     /// Get mutable boot flag value memory mapping.
get_mutable_boot_flag_val(&mut self) -> Result<&mut MmapMut, AconfigdError>357     fn get_mutable_boot_flag_val(&mut self) -> Result<&mut MmapMut, AconfigdError> {
358         if self.mutable_boot_flag_val.is_none() {
359             // SAFETY: safety is ensured that all writes to the persist file is thru this
360             // memory mapping, and there are no concurrent writes
361             self.mutable_boot_flag_val = unsafe {
362                 Some(Self::get_mutable_file_mapping(&self.storage_record.boot_flag_val)?)
363             };
364         }
365         Ok(self.mutable_boot_flag_val.as_mut().unwrap())
366     }
367 
368     /// Get mutable boot flag info memory mapping.
get_mutable_boot_flag_info(&mut self) -> Result<&mut MmapMut, AconfigdError>369     fn get_mutable_boot_flag_info(&mut self) -> Result<&mut MmapMut, AconfigdError> {
370         if self.mutable_boot_flag_info.is_none() {
371             // SAFETY: safety is ensured that all writes to the persist file is thru this
372             // memory mapping, and there are no concurrent writes
373             self.mutable_boot_flag_info = unsafe {
374                 Some(Self::get_mutable_file_mapping(&self.storage_record.boot_flag_info)?)
375             };
376         }
377         Ok(self.mutable_boot_flag_info.as_mut().unwrap())
378     }
379 
380     /// Get package and flag query context
get_package_flag_context( &mut self, package: &str, flag: &str, ) -> Result<PackageFlagContext, AconfigdError>381     pub(crate) fn get_package_flag_context(
382         &mut self,
383         package: &str,
384         flag: &str,
385     ) -> Result<PackageFlagContext, AconfigdError> {
386         let mut context = PackageFlagContext {
387             package: package.to_string(),
388             flag: flag.to_string(),
389             package_exists: false,
390             flag_exists: false,
391             value_type: FlagValueType::Boolean,
392             flag_index: 0,
393         };
394 
395         if package.is_empty() {
396             return Ok(context);
397         }
398 
399         let package_context =
400             get_package_read_context(self.get_package_map()?, package).map_err(|errmsg| {
401                 AconfigdError::FailToGetPackageContext { package: package.to_string(), errmsg }
402             })?;
403 
404         if let Some(pkg) = package_context {
405             context.package_exists = true;
406             if flag.is_empty() {
407                 return Ok(context);
408             }
409 
410             let flag_context = get_flag_read_context(self.get_flag_map()?, pkg.package_id, flag)
411                 .map_err(|errmsg| AconfigdError::FailToGetFlagContext {
412                     flag: package.to_string() + "." + flag,
413                     errmsg,
414                 })?;
415 
416             if let Some(flg) = flag_context {
417                 context.flag_exists = true;
418                 context.value_type = FlagValueType::try_from(flg.flag_type).map_err(|errmsg| {
419                     AconfigdError::InvalidFlagValueType {
420                         flag: package.to_string() + "." + flag,
421                         errmsg,
422                     }
423                 })?;
424                 context.flag_index = pkg.boolean_start_index + flg.flag_index as u32;
425             }
426         }
427 
428         Ok(context)
429     }
430 
431     /// Check if has an aconfig package
has_package(&mut self, package: &str) -> Result<bool, AconfigdError>432     pub(crate) fn has_package(&mut self, package: &str) -> Result<bool, AconfigdError> {
433         let context = self.get_package_flag_context(package, "")?;
434         Ok(context.package_exists)
435     }
436 
437     /// Get flag attribute bitfield
get_flag_attribute( &mut self, context: &PackageFlagContext, ) -> Result<u8, AconfigdError>438     pub(crate) fn get_flag_attribute(
439         &mut self,
440         context: &PackageFlagContext,
441     ) -> Result<u8, AconfigdError> {
442         if !context.flag_exists {
443             return Err(AconfigdError::FlagDoesNotExist {
444                 flag: context.package.to_string() + "." + &context.flag,
445             });
446         }
447 
448         let flag_info_file = self.get_persist_flag_info()?;
449         Ok(aconfig_storage_read_api::get_flag_attribute(
450             flag_info_file,
451             context.value_type,
452             context.flag_index,
453         )
454         .map_err(|errmsg| AconfigdError::FailToGetFlagAttribute {
455             flag: context.package.to_string() + "." + &context.flag,
456             errmsg,
457         })?)
458     }
459 
460     /// Get flag value from a mapped file
get_flag_value_from_file( file: &[u8], context: &PackageFlagContext, ) -> Result<String, AconfigdError>461     fn get_flag_value_from_file(
462         file: &[u8],
463         context: &PackageFlagContext,
464     ) -> Result<String, AconfigdError> {
465         if !context.flag_exists {
466             return Err(AconfigdError::FlagDoesNotExist {
467                 flag: context.package.to_string() + "." + &context.flag,
468             });
469         }
470 
471         match context.value_type {
472             FlagValueType::Boolean => {
473                 let value = get_boolean_flag_value(file, context.flag_index).map_err(|errmsg| {
474                     AconfigdError::FailToGetFlagValue {
475                         flag: context.package.to_string() + "." + &context.flag,
476                         errmsg,
477                     }
478                 })?;
479                 if value {
480                     Ok(String::from("true"))
481                 } else {
482                     Ok(String::from("false"))
483                 }
484             }
485         }
486     }
487 
488     /// Get server flag value
get_server_flag_value( &mut self, context: &PackageFlagContext, ) -> Result<String, AconfigdError>489     pub(crate) fn get_server_flag_value(
490         &mut self,
491         context: &PackageFlagContext,
492     ) -> Result<String, AconfigdError> {
493         let attribute = self.get_flag_attribute(context)?;
494         if (attribute & FlagInfoBit::HasServerOverride as u8) == 0 {
495             return Ok(String::new());
496         }
497 
498         let flag_val_file = self.get_persist_flag_val()?;
499         Self::get_flag_value_from_file(flag_val_file, context)
500     }
501 
502     /// Get boot flag value
get_boot_flag_value( &mut self, context: &PackageFlagContext, ) -> Result<String, AconfigdError>503     pub(crate) fn get_boot_flag_value(
504         &mut self,
505         context: &PackageFlagContext,
506     ) -> Result<String, AconfigdError> {
507         // SAFETY: safety is ensured as we are only read from the memory mapping
508         let flag_val_file = unsafe { self.get_boot_flag_val()? };
509         Self::get_flag_value_from_file(flag_val_file, context)
510     }
511 
512     /// Get default flag value
get_default_flag_value( &mut self, context: &PackageFlagContext, ) -> Result<String, AconfigdError>513     pub(crate) fn get_default_flag_value(
514         &mut self,
515         context: &PackageFlagContext,
516     ) -> Result<String, AconfigdError> {
517         let flag_val_file = self.get_flag_val()?;
518         Self::get_flag_value_from_file(flag_val_file, context)
519     }
520 
521     /// Get local flag value
get_local_flag_value( &mut self, context: &PackageFlagContext, ) -> Result<String, AconfigdError>522     pub(crate) fn get_local_flag_value(
523         &mut self,
524         context: &PackageFlagContext,
525     ) -> Result<String, AconfigdError> {
526         let attribute = self.get_flag_attribute(context)?;
527         if (attribute & FlagInfoBit::HasLocalOverride as u8) == 0 {
528             return Ok(String::new());
529         }
530 
531         let pb =
532             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
533 
534         for entry in pb.overrides {
535             if entry.package_name() == context.package && entry.flag_name() == context.flag {
536                 return Ok(String::from(entry.flag_value()));
537             }
538         }
539 
540         Err(AconfigdError::FlagHasNoLocalOverride {
541             flag: context.package.to_string() + "." + &context.flag,
542         })
543     }
544 
545     /// Set flag value to file
set_flag_value_to_file( file: &mut MmapMut, context: &PackageFlagContext, value: &str, ) -> Result<(), AconfigdError>546     pub(crate) fn set_flag_value_to_file(
547         file: &mut MmapMut,
548         context: &PackageFlagContext,
549         value: &str,
550     ) -> Result<(), AconfigdError> {
551         match context.value_type {
552             FlagValueType::Boolean => {
553                 if value != "true" && value != "false" {
554                     return Err(AconfigdError::InvalidFlagValue {
555                         flag: context.package.to_string() + "." + &context.flag,
556                         value: value.to_string(),
557                     });
558                 }
559                 set_boolean_flag_value(file, context.flag_index, value == "true").map_err(
560                     |errmsg| AconfigdError::FailToSetFlagValue {
561                         flag: context.package.to_string() + "." + &context.flag,
562                         errmsg,
563                     },
564                 )?;
565             }
566         }
567 
568         Ok(())
569     }
570 
571     /// Set flag has server override to file
set_flag_has_server_override_to_file( file: &mut MmapMut, context: &PackageFlagContext, value: bool, ) -> Result<(), AconfigdError>572     fn set_flag_has_server_override_to_file(
573         file: &mut MmapMut,
574         context: &PackageFlagContext,
575         value: bool,
576     ) -> Result<(), AconfigdError> {
577         set_flag_has_server_override(file, context.value_type, context.flag_index, value).map_err(
578             |errmsg| AconfigdError::FailToSetFlagHasServerOverride {
579                 flag: context.package.to_string() + "." + &context.flag,
580                 errmsg,
581             },
582         )?;
583 
584         Ok(())
585     }
586 
587     /// Set flag has local override to file
set_flag_has_local_override_to_file( file: &mut MmapMut, context: &PackageFlagContext, value: bool, ) -> Result<(), AconfigdError>588     pub(crate) fn set_flag_has_local_override_to_file(
589         file: &mut MmapMut,
590         context: &PackageFlagContext,
591         value: bool,
592     ) -> Result<(), AconfigdError> {
593         set_flag_has_local_override(file, context.value_type, context.flag_index, value).map_err(
594             |errmsg| AconfigdError::FailToSetFlagHasLocalOverride {
595                 flag: context.package.to_string() + "." + &context.flag,
596                 errmsg,
597             },
598         )?;
599 
600         Ok(())
601     }
602 
603     /// Server override a flag
stage_server_override( &mut self, context: &PackageFlagContext, value: &str, ) -> Result<(), AconfigdError>604     pub(crate) fn stage_server_override(
605         &mut self,
606         context: &PackageFlagContext,
607         value: &str,
608     ) -> Result<(), AconfigdError> {
609         let attribute = self.get_flag_attribute(context)?;
610         if (attribute & FlagInfoBit::IsReadWrite as u8) == 0 {
611             return Err(AconfigdError::FlagIsReadOnly {
612                 flag: context.package.to_string() + "." + &context.flag,
613             });
614         }
615 
616         let flag_val_file = self.get_persist_flag_val()?;
617         Self::set_flag_value_to_file(flag_val_file, context, value)?;
618 
619         let flag_info_file = self.get_persist_flag_info()?;
620         Self::set_flag_has_server_override_to_file(flag_info_file, context, true)?;
621 
622         Ok(())
623     }
624 
625     /// Stage local override of a flag
stage_local_override( &mut self, context: &PackageFlagContext, value: &str, ) -> Result<(), AconfigdError>626     pub(crate) fn stage_local_override(
627         &mut self,
628         context: &PackageFlagContext,
629         value: &str,
630     ) -> Result<(), AconfigdError> {
631         let attribute = self.get_flag_attribute(context)?;
632         if (attribute & FlagInfoBit::IsReadWrite as u8) == 0 {
633             return Err(AconfigdError::FlagIsReadOnly {
634                 flag: context.package.to_string() + "." + &context.flag,
635             });
636         }
637 
638         let mut exist = false;
639         let mut pb =
640             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
641         for entry in &mut pb.overrides {
642             if entry.package_name() == context.package && entry.flag_name() == context.flag {
643                 entry.set_flag_value(String::from(value));
644                 exist = true;
645                 break;
646             }
647         }
648         if !exist {
649             let mut new_entry = ProtoFlagOverride::new();
650             new_entry.set_package_name(context.package.clone());
651             new_entry.set_flag_name(context.flag.clone());
652             new_entry.set_flag_value(String::from(value));
653             pb.overrides.push(new_entry);
654         }
655 
656         write_pb_to_file::<ProtoLocalFlagOverrides>(&pb, &self.storage_record.local_overrides)?;
657 
658         let flag_info_file = self.get_persist_flag_info()?;
659         Self::set_flag_has_local_override_to_file(flag_info_file, context, true)?;
660 
661         Ok(())
662     }
663 
664     /// Stage and apply local override of a flag
stage_and_apply_local_override( &mut self, context: &PackageFlagContext, value: &str, ) -> Result<(), AconfigdError>665     pub(crate) fn stage_and_apply_local_override(
666         &mut self,
667         context: &PackageFlagContext,
668         value: &str,
669     ) -> Result<(), AconfigdError> {
670         self.stage_local_override(&context, value)?;
671         let mut mut_boot_flag_val = self.get_mutable_boot_flag_val()?;
672         Self::set_flag_value_to_file(&mut mut_boot_flag_val, &context, value)?;
673         let mut mut_boot_flag_info = self.get_mutable_boot_flag_info()?;
674         Self::set_flag_has_local_override_to_file(&mut mut_boot_flag_info, &context, true)?;
675         Ok(())
676     }
677 
678     /// Apply all staged local overrides
apply_staged_local_overrides(&mut self) -> Result<(), AconfigdError>679     fn apply_staged_local_overrides(&mut self) -> Result<(), AconfigdError> {
680         let pb =
681             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
682 
683         for entry in pb.overrides {
684             let context = self.get_package_flag_context(entry.package_name(), entry.flag_name())?;
685             let mut flag_val_file = self.get_mutable_boot_flag_val()?;
686             Self::set_flag_value_to_file(&mut flag_val_file, &context, entry.flag_value())?;
687         }
688 
689         Ok(())
690     }
691 
692     /// Apply both server and local overrides
apply_all_staged_overrides(&mut self) -> Result<(), AconfigdError>693     pub(crate) fn apply_all_staged_overrides(&mut self) -> Result<(), AconfigdError> {
694         copy_file(
695             &self.storage_record.persist_flag_val,
696             &self.storage_record.boot_flag_val,
697             0o644,
698         )?;
699         copy_file(
700             &self.storage_record.persist_flag_info,
701             &self.storage_record.boot_flag_info,
702             0o644,
703         )?;
704         self.apply_staged_local_overrides()?;
705         Ok(())
706     }
707 
708     /// Get all current server overrides
get_all_server_overrides( &mut self, ) -> Result<Vec<FlagValueSummary>, AconfigdError>709     pub(crate) fn get_all_server_overrides(
710         &mut self,
711     ) -> Result<Vec<FlagValueSummary>, AconfigdError> {
712         let listed_flags = list_flags_with_info(
713             &self.storage_record.persist_package_map.display().to_string(),
714             &self.storage_record.persist_flag_map.display().to_string(),
715             &self.storage_record.persist_flag_val.display().to_string(),
716             &self.storage_record.persist_flag_info.display().to_string(),
717         )
718         .map_err(|errmsg| AconfigdError::FailToListFlagsWithInfo {
719             container: self.storage_record.container.clone(),
720             errmsg,
721         })?;
722 
723         Ok(listed_flags
724             .into_iter()
725             .filter(|f| f.has_server_override)
726             .map(|f| FlagValueSummary {
727                 package_name: f.package_name,
728                 flag_name: f.flag_name,
729                 flag_value: f.flag_value,
730                 value_type: f.value_type,
731             })
732             .collect())
733     }
734 
735     /// Get all local overrides
get_all_local_overrides( &mut self, ) -> Result<Vec<ProtoFlagOverride>, AconfigdError>736     pub(crate) fn get_all_local_overrides(
737         &mut self,
738     ) -> Result<Vec<ProtoFlagOverride>, AconfigdError> {
739         let pb =
740             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
741         Ok(pb.overrides)
742     }
743 
744     /// Remove a local flag override
remove_local_override( &mut self, context: &PackageFlagContext, ) -> Result<(), AconfigdError>745     pub(crate) fn remove_local_override(
746         &mut self,
747         context: &PackageFlagContext,
748     ) -> Result<(), AconfigdError> {
749         let attribute = self.get_flag_attribute(context)?;
750         if (attribute & FlagInfoBit::HasLocalOverride as u8) == 0 {
751             return Err(AconfigdError::FlagHasNoLocalOverride {
752                 flag: context.package.to_string() + "." + &context.flag,
753             });
754         }
755 
756         let mut pb =
757             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
758         pb.overrides = pb
759             .overrides
760             .into_iter()
761             .filter(|f| f.package_name() != context.package || f.flag_name() != context.flag)
762             .collect();
763         write_pb_to_file::<ProtoLocalFlagOverrides>(&pb, &self.storage_record.local_overrides)?;
764 
765         let flag_info_file = self.get_persist_flag_info()?;
766         Self::set_flag_has_local_override_to_file(flag_info_file, context, false)?;
767 
768         Ok(())
769     }
770 
771     /// Remove all local flag overrides
remove_all_local_overrides(&mut self) -> Result<(), AconfigdError>772     pub(crate) fn remove_all_local_overrides(&mut self) -> Result<(), AconfigdError> {
773         let pb =
774             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
775 
776         for entry in pb.overrides {
777             let context = self.get_package_flag_context(entry.package_name(), entry.flag_name())?;
778             let attribute = self.get_flag_attribute(&context)?;
779             if (attribute & FlagInfoBit::HasLocalOverride as u8) == 0 {
780                 return Err(AconfigdError::FlagHasNoLocalOverride {
781                     flag: context.package.to_string() + "." + &context.flag,
782                 });
783             }
784 
785             let flag_info_file = self.get_persist_flag_info()?;
786             Self::set_flag_has_local_override_to_file(flag_info_file, &context, false)?;
787         }
788 
789         write_pb_to_file::<ProtoLocalFlagOverrides>(
790             &ProtoLocalFlagOverrides::new(),
791             &self.storage_record.local_overrides,
792         )?;
793 
794         Ok(())
795     }
796 
797     /// Clean up, it cannot be implemented as the drop trait as it needs to return a Result
remove_persist_files(&mut self) -> Result<(), AconfigdError>798     pub(crate) fn remove_persist_files(&mut self) -> Result<(), AconfigdError> {
799         remove_file(&self.storage_record.persist_package_map)?;
800         remove_file(&self.storage_record.persist_flag_map)?;
801         remove_file(&self.storage_record.persist_flag_val)?;
802         remove_file(&self.storage_record.persist_flag_info)?;
803         remove_file(&self.storage_record.local_overrides)
804     }
805 
806     /// get flag snapshot
get_flag_snapshot( &mut self, package: &str, flag: &str, ) -> Result<Option<FlagSnapshot>, AconfigdError>807     pub(crate) fn get_flag_snapshot(
808         &mut self,
809         package: &str,
810         flag: &str,
811     ) -> Result<Option<FlagSnapshot>, AconfigdError> {
812         let context = self.get_package_flag_context(package, flag)?;
813         if !context.flag_exists {
814             return Ok(None);
815         }
816 
817         let attribute = self.get_flag_attribute(&context)?;
818         let server_value = self.get_server_flag_value(&context)?;
819         let local_value = self.get_local_flag_value(&context)?;
820         let boot_value = self.get_boot_flag_value(&context)?;
821         let default_value = self.get_default_flag_value(&context)?;
822 
823         Ok(Some(FlagSnapshot {
824             container: self.storage_record.container.clone(),
825             package: package.to_string(),
826             flag: flag.to_string(),
827             server_value,
828             local_value,
829             boot_value,
830             default_value,
831             is_readwrite: attribute & FlagInfoBit::IsReadWrite as u8 != 0,
832             has_server_override: attribute & FlagInfoBit::HasServerOverride as u8 != 0,
833             has_local_override: attribute & FlagInfoBit::HasLocalOverride as u8 != 0,
834         }))
835     }
836 
837     /// list flags in a package
list_flags_in_package( &mut self, package: &str, ) -> Result<Vec<FlagSnapshot>, AconfigdError>838     pub(crate) fn list_flags_in_package(
839         &mut self,
840         package: &str,
841     ) -> Result<Vec<FlagSnapshot>, AconfigdError> {
842         if !self.has_package(package)? {
843             return Ok(Vec::new());
844         }
845 
846         let mut snapshots: Vec<_> = list_flags_with_info(
847             &self.storage_record.persist_package_map.display().to_string(),
848             &self.storage_record.persist_flag_map.display().to_string(),
849             &self.storage_record.persist_flag_val.display().to_string(),
850             &self.storage_record.persist_flag_info.display().to_string(),
851         )
852         .map_err(|errmsg| AconfigdError::FailToListFlagsWithInfo {
853             container: self.storage_record.container.clone(),
854             errmsg,
855         })?
856         .into_iter()
857         .filter(|f| f.package_name == package)
858         .map(|f| FlagSnapshot {
859             container: self.storage_record.container.clone(),
860             package: f.package_name.clone(),
861             flag: f.flag_name.clone(),
862             server_value: if f.has_server_override { f.flag_value.clone() } else { String::new() },
863             local_value: String::new(),
864             boot_value: String::new(),
865             default_value: String::new(),
866             is_readwrite: f.is_readwrite,
867             has_server_override: f.has_server_override,
868             has_local_override: f.has_local_override,
869         })
870         .collect();
871 
872         let mut flag_index = HashMap::new();
873         for (i, f) in snapshots.iter().enumerate() {
874             flag_index.insert(f.package.clone() + "/" + &f.flag, i);
875         }
876 
877         let mut flags: Vec<_> = list_flags(
878             &self.storage_record.persist_package_map.display().to_string(),
879             &self.storage_record.persist_flag_map.display().to_string(),
880             &self.storage_record.boot_flag_val.display().to_string(),
881         )
882         .map_err(|errmsg| AconfigdError::FailToListFlags {
883             container: self.storage_record.container.clone(),
884             errmsg,
885         })?
886         .into_iter()
887         .filter(|f| f.package_name == package)
888         .collect();
889 
890         for f in flags.iter() {
891             let full_flag_name = f.package_name.clone() + "/" + &f.flag_name;
892             let index =
893                 flag_index.get(&full_flag_name).ok_or(AconfigdError::InternalError(anyhow!(
894                     "Flag {}.{} appears in boot files but not in persist fliles",
895                     &f.package_name,
896                     &f.flag_name,
897                 )))?;
898             snapshots[*index].boot_value = f.flag_value.clone();
899         }
900 
901         flags = list_flags(
902             &self.storage_record.persist_package_map.display().to_string(),
903             &self.storage_record.persist_flag_map.display().to_string(),
904             &self.storage_record.default_flag_val.display().to_string(),
905         )
906         .map_err(|errmsg| AconfigdError::FailToListFlags {
907             container: self.storage_record.container.clone(),
908             errmsg,
909         })?
910         .into_iter()
911         .filter(|f| f.package_name == package)
912         .collect();
913 
914         for f in flags.iter() {
915             let full_flag_name = f.package_name.clone() + "/" + &f.flag_name;
916             let index =
917                 flag_index.get(&full_flag_name).ok_or(AconfigdError::InternalError(anyhow!(
918                     "Flag {}.{} appears in default files but not in persist fliles",
919                     &f.package_name,
920                     &f.flag_name,
921                 )))?;
922             snapshots[*index].default_value = f.flag_value.clone();
923         }
924 
925         let pb =
926             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
927 
928         for entry in pb.overrides {
929             let full_flag_name = entry.package_name().to_string() + "/" + entry.flag_name();
930             if let Some(index) = flag_index.get(&full_flag_name) {
931                 snapshots[*index].local_value = entry.flag_value().to_string();
932             }
933         }
934 
935         Ok(snapshots)
936     }
937 
938     /// list all flags in a container
list_all_flags(&mut self) -> Result<Vec<FlagSnapshot>, AconfigdError>939     pub(crate) fn list_all_flags(&mut self) -> Result<Vec<FlagSnapshot>, AconfigdError> {
940         let mut snapshots: Vec<_> = list_flags_with_info(
941             &self.storage_record.persist_package_map.display().to_string(),
942             &self.storage_record.persist_flag_map.display().to_string(),
943             &self.storage_record.persist_flag_val.display().to_string(),
944             &self.storage_record.persist_flag_info.display().to_string(),
945         )
946         .map_err(|errmsg| AconfigdError::FailToListFlagsWithInfo {
947             container: self.storage_record.container.clone(),
948             errmsg,
949         })?
950         .into_iter()
951         .map(|f| FlagSnapshot {
952             container: self.storage_record.container.clone(),
953             package: f.package_name.clone(),
954             flag: f.flag_name.clone(),
955             server_value: if f.has_server_override { f.flag_value.clone() } else { String::new() },
956             local_value: String::new(),
957             boot_value: String::new(),
958             default_value: String::new(),
959             is_readwrite: f.is_readwrite,
960             has_server_override: f.has_server_override,
961             has_local_override: f.has_local_override,
962         })
963         .collect();
964 
965         let mut flag_index = HashMap::new();
966         for (i, f) in snapshots.iter().enumerate() {
967             flag_index.insert(f.package.clone() + "/" + &f.flag, i);
968         }
969 
970         let mut flags: Vec<_> = list_flags(
971             &self.storage_record.persist_package_map.display().to_string(),
972             &self.storage_record.persist_flag_map.display().to_string(),
973             &self.storage_record.boot_flag_val.display().to_string(),
974         )
975         .map_err(|errmsg| AconfigdError::FailToListFlags {
976             container: self.storage_record.container.clone(),
977             errmsg,
978         })?
979         .into_iter()
980         .collect();
981 
982         for f in flags.iter() {
983             let full_flag_name = f.package_name.clone() + "/" + &f.flag_name;
984             let index =
985                 flag_index.get(&full_flag_name).ok_or(AconfigdError::InternalError(anyhow!(
986                     "Flag {}.{} appears in boot files but not in persist fliles",
987                     &f.package_name,
988                     &f.flag_name,
989                 )))?;
990             snapshots[*index].boot_value = f.flag_value.clone();
991         }
992 
993         flags = list_flags(
994             &self.storage_record.persist_package_map.display().to_string(),
995             &self.storage_record.persist_flag_map.display().to_string(),
996             &self.storage_record.default_flag_val.display().to_string(),
997         )
998         .map_err(|errmsg| AconfigdError::FailToListFlags {
999             container: self.storage_record.container.clone(),
1000             errmsg,
1001         })?
1002         .into_iter()
1003         .collect();
1004 
1005         for f in flags.iter() {
1006             let full_flag_name = f.package_name.clone() + "/" + &f.flag_name;
1007             let index =
1008                 flag_index.get(&full_flag_name).ok_or(AconfigdError::InternalError(anyhow!(
1009                     "Flag {}.{} appears in default files but not in persist fliles",
1010                     &f.package_name,
1011                     &f.flag_name,
1012                 )))?;
1013             snapshots[*index].default_value = f.flag_value.clone();
1014         }
1015 
1016         let pb =
1017             read_pb_from_file::<ProtoLocalFlagOverrides>(&self.storage_record.local_overrides)?;
1018 
1019         for entry in pb.overrides {
1020             let full_flag_name = entry.package_name().to_string() + "/" + entry.flag_name();
1021             if let Some(index) = flag_index.get(&full_flag_name) {
1022                 snapshots[*index].local_value = entry.flag_value().to_string();
1023             }
1024         }
1025 
1026         Ok(snapshots)
1027     }
1028 }
1029 
1030 #[cfg(test)]
1031 mod tests {
1032     use super::*;
1033     use crate::test_utils::{has_same_content, ContainerMock, StorageRootDirMock};
1034     use aconfig_storage_file::StoredFlagType;
1035 
create_mock_storage_files( container: &ContainerMock, root_dir: &StorageRootDirMock, ) -> StorageFiles1036     fn create_mock_storage_files(
1037         container: &ContainerMock,
1038         root_dir: &StorageRootDirMock,
1039     ) -> StorageFiles {
1040         StorageFiles::from_container(
1041             &container.name,
1042             &container.package_map,
1043             &container.flag_map,
1044             &container.flag_val,
1045             &container.flag_info,
1046             &root_dir.tmp_dir.path(),
1047         )
1048         .unwrap()
1049     }
1050 
1051     #[test]
test_create_storage_file_from_container()1052     fn test_create_storage_file_from_container() {
1053         let container = ContainerMock::new();
1054         let root_dir = StorageRootDirMock::new();
1055         let storage_files = create_mock_storage_files(&container, &root_dir);
1056 
1057         let expected_record = StorageRecord {
1058             version: 1,
1059             container: String::from("mockup"),
1060             default_package_map: container.package_map.clone(),
1061             default_flag_map: container.flag_map.clone(),
1062             default_flag_val: container.flag_val.clone(),
1063             default_flag_info: container.flag_info.clone(),
1064             persist_package_map: root_dir.maps_dir.join("mockup.package.map"),
1065             persist_flag_map: root_dir.maps_dir.join("mockup.flag.map"),
1066             persist_flag_val: root_dir.flags_dir.join("mockup.val"),
1067             persist_flag_info: root_dir.flags_dir.join("mockup.info"),
1068             local_overrides: root_dir.flags_dir.join("mockup_local_overrides.pb"),
1069             boot_flag_val: root_dir.boot_dir.join("mockup.val"),
1070             boot_flag_info: root_dir.boot_dir.join("mockup.info"),
1071             digest: get_files_digest(
1072                 &[
1073                     container.package_map.as_path(),
1074                     container.flag_map.as_path(),
1075                     container.flag_val.as_path(),
1076                     container.flag_info.as_path(),
1077                 ][..],
1078             )
1079             .unwrap(),
1080         };
1081 
1082         let expected_storage_files = StorageFiles {
1083             storage_record: expected_record,
1084             package_map: None,
1085             flag_map: None,
1086             flag_val: None,
1087             boot_flag_val: None,
1088             boot_flag_info: None,
1089             persist_flag_val: None,
1090             persist_flag_info: None,
1091             mutable_boot_flag_val: None,
1092             mutable_boot_flag_info: None,
1093         };
1094 
1095         assert_eq!(storage_files, expected_storage_files);
1096 
1097         assert!(has_same_content(
1098             &container.package_map,
1099             &storage_files.storage_record.persist_package_map
1100         ));
1101         assert!(has_same_content(
1102             &container.flag_map,
1103             &storage_files.storage_record.persist_flag_map
1104         ));
1105         assert!(has_same_content(
1106             &container.flag_val,
1107             &storage_files.storage_record.persist_flag_val
1108         ));
1109         assert!(has_same_content(
1110             &container.flag_info,
1111             &storage_files.storage_record.persist_flag_info
1112         ));
1113         assert!(has_same_content(&container.flag_val, &storage_files.storage_record.boot_flag_val));
1114         assert!(has_same_content(
1115             &container.flag_info,
1116             &storage_files.storage_record.boot_flag_info
1117         ));
1118         assert!(storage_files.storage_record.local_overrides.exists());
1119     }
1120 
1121     #[test]
test_create_storage_file_from_pb()1122     fn test_create_storage_file_from_pb() {
1123         let root_dir = StorageRootDirMock::new();
1124         let container = ContainerMock::new();
1125 
1126         let persist_package_map = root_dir.maps_dir.join("mockup.package.map");
1127         let persist_flag_map = root_dir.maps_dir.join("mockup.flag.map");
1128         let persist_flag_val = root_dir.flags_dir.join("mockup.val");
1129         let persist_flag_info = root_dir.flags_dir.join("mockup.info");
1130         copy_file(&container.package_map, &persist_package_map, 0o444).unwrap();
1131         copy_file(&container.flag_map, &persist_flag_map, 0o444).unwrap();
1132         copy_file(&container.flag_val, &persist_flag_val, 0o644).unwrap();
1133         copy_file(&container.flag_info, &persist_flag_info, 0o644).unwrap();
1134 
1135         let mut pb = ProtoPersistStorageRecord::new();
1136         pb.set_version(123);
1137         pb.set_container("mockup".to_string());
1138         pb.set_package_map(container.package_map.display().to_string());
1139         pb.set_flag_map(container.flag_map.display().to_string());
1140         pb.set_flag_val(container.flag_val.display().to_string());
1141         pb.set_flag_info(container.flag_info.display().to_string());
1142         pb.set_digest(String::from("abc"));
1143 
1144         let storage_files = StorageFiles::from_pb(&pb, &root_dir.tmp_dir.path()).unwrap();
1145 
1146         let expected_record = StorageRecord {
1147             version: 123,
1148             container: String::from("mockup"),
1149             default_package_map: container.package_map.clone(),
1150             default_flag_map: container.flag_map.clone(),
1151             default_flag_val: container.flag_val.clone(),
1152             default_flag_info: container.flag_info.clone(),
1153             persist_package_map: root_dir.maps_dir.join("mockup.package.map"),
1154             persist_flag_map: root_dir.maps_dir.join("mockup.flag.map"),
1155             persist_flag_val: root_dir.flags_dir.join("mockup.val"),
1156             persist_flag_info: root_dir.flags_dir.join("mockup.info"),
1157             local_overrides: root_dir.flags_dir.join("mockup_local_overrides.pb"),
1158             boot_flag_val: root_dir.boot_dir.join("mockup.val"),
1159             boot_flag_info: root_dir.boot_dir.join("mockup.info"),
1160             digest: String::from("abc"),
1161         };
1162 
1163         let expected_storage_files = StorageFiles {
1164             storage_record: expected_record,
1165             package_map: None,
1166             flag_map: None,
1167             flag_val: None,
1168             boot_flag_val: None,
1169             boot_flag_info: None,
1170             persist_flag_val: None,
1171             persist_flag_info: None,
1172             mutable_boot_flag_val: None,
1173             mutable_boot_flag_info: None,
1174         };
1175 
1176         assert!(has_same_content(
1177             &storage_files.storage_record.persist_flag_val,
1178             &storage_files.storage_record.boot_flag_val
1179         ));
1180         assert!(has_same_content(
1181             &storage_files.storage_record.persist_flag_info,
1182             &storage_files.storage_record.boot_flag_info
1183         ));
1184 
1185         assert_eq!(storage_files, expected_storage_files);
1186     }
1187 
1188     #[test]
test_get_package_flag_context()1189     fn test_get_package_flag_context() {
1190         let container = ContainerMock::new();
1191         let root_dir = StorageRootDirMock::new();
1192         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1193 
1194         let mut context = PackageFlagContext {
1195             package: String::from("not_exist"),
1196             flag: String::new(),
1197             package_exists: false,
1198             flag_exists: false,
1199             value_type: FlagValueType::Boolean,
1200             flag_index: 0,
1201         };
1202         let mut actual_context = storage_files.get_package_flag_context("not_exist", "").unwrap();
1203         assert_eq!(context, actual_context);
1204 
1205         context.package = String::from("com.android.aconfig.storage.test_1");
1206         context.package_exists = true;
1207         actual_context = storage_files
1208             .get_package_flag_context("com.android.aconfig.storage.test_1", "")
1209             .unwrap();
1210         assert_eq!(context, actual_context);
1211 
1212         context.flag = String::from("not_exist");
1213         actual_context = storage_files
1214             .get_package_flag_context("com.android.aconfig.storage.test_1", "not_exist")
1215             .unwrap();
1216         assert_eq!(context, actual_context);
1217 
1218         context.flag = String::from("enabled_rw");
1219         context.flag_exists = true;
1220         context.flag_index = 2;
1221         actual_context = storage_files
1222             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1223             .unwrap();
1224         assert_eq!(context, actual_context);
1225 
1226         context.package = String::from("com.android.aconfig.storage.test_2");
1227         context.flag = String::from("disabled_rw");
1228         context.flag_index = 3;
1229         actual_context = storage_files
1230             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1231             .unwrap();
1232         assert_eq!(context, actual_context);
1233     }
1234 
1235     #[test]
test_has_package()1236     fn test_has_package() {
1237         let container = ContainerMock::new();
1238         let root_dir = StorageRootDirMock::new();
1239         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1240         assert!(!storage_files.has_package("not_exist").unwrap());
1241         assert!(storage_files.has_package("com.android.aconfig.storage.test_1").unwrap());
1242     }
1243 
1244     #[test]
test_get_flag_attribute()1245     fn test_get_flag_attribute() {
1246         let container = ContainerMock::new();
1247         let root_dir = StorageRootDirMock::new();
1248         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1249         let mut context = storage_files
1250             .get_package_flag_context("com.android.aconfig.storage.test_1", "not_exist")
1251             .unwrap();
1252         assert!(storage_files.get_flag_attribute(&context).is_err());
1253 
1254         context = storage_files
1255             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1256             .unwrap();
1257         let attribute = storage_files.get_flag_attribute(&context).unwrap();
1258         assert!(attribute & (FlagInfoBit::IsReadWrite as u8) != 0);
1259         assert!(attribute & (FlagInfoBit::HasServerOverride as u8) == 0);
1260         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) == 0);
1261     }
1262 
1263     #[test]
test_get_server_flag_value()1264     fn test_get_server_flag_value() {
1265         let container = ContainerMock::new();
1266         let root_dir = StorageRootDirMock::new();
1267         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1268         let context = storage_files
1269             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1270             .unwrap();
1271 
1272         assert_eq!(&storage_files.get_server_flag_value(&context).unwrap(), "");
1273         storage_files.stage_server_override(&context, "false").unwrap();
1274         assert_eq!(&storage_files.get_server_flag_value(&context).unwrap(), "false");
1275         storage_files.stage_server_override(&context, "true").unwrap();
1276         assert_eq!(&storage_files.get_server_flag_value(&context).unwrap(), "true");
1277     }
1278 
1279     #[test]
test_get_boot_flag_value()1280     fn test_get_boot_flag_value() {
1281         let container = ContainerMock::new();
1282         let root_dir = StorageRootDirMock::new();
1283         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1284         let mut context = storage_files
1285             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1286             .unwrap();
1287         assert_eq!(storage_files.get_boot_flag_value(&context).unwrap(), "true");
1288         context = storage_files
1289             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1290             .unwrap();
1291         assert_eq!(storage_files.get_boot_flag_value(&context).unwrap(), "false");
1292     }
1293 
1294     #[test]
test_get_default_flag_value()1295     fn test_get_default_flag_value() {
1296         let container = ContainerMock::new();
1297         let root_dir = StorageRootDirMock::new();
1298         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1299         let mut context = storage_files
1300             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1301             .unwrap();
1302         assert_eq!(storage_files.get_default_flag_value(&context).unwrap(), "true");
1303         context = storage_files
1304             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1305             .unwrap();
1306         assert_eq!(storage_files.get_default_flag_value(&context).unwrap(), "false");
1307     }
1308 
1309     #[test]
test_get_local_flag_value()1310     fn test_get_local_flag_value() {
1311         let container = ContainerMock::new();
1312         let root_dir = StorageRootDirMock::new();
1313         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1314         let context = storage_files
1315             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1316             .unwrap();
1317         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "");
1318         storage_files.stage_local_override(&context, "false").unwrap();
1319         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "false");
1320         storage_files.stage_local_override(&context, "true").unwrap();
1321         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "true");
1322     }
1323 
1324     #[test]
test_stage_server_override()1325     fn test_stage_server_override() {
1326         let container = ContainerMock::new();
1327         let root_dir = StorageRootDirMock::new();
1328         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1329         let context = storage_files
1330             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1331             .unwrap();
1332         storage_files.stage_server_override(&context, "false").unwrap();
1333         assert_eq!(&storage_files.get_server_flag_value(&context).unwrap(), "false");
1334         let attribute = storage_files.get_flag_attribute(&context).unwrap();
1335         assert!(attribute & (FlagInfoBit::HasServerOverride as u8) != 0);
1336     }
1337 
1338     #[test]
test_stage_local_override()1339     fn test_stage_local_override() {
1340         let container = ContainerMock::new();
1341         let root_dir = StorageRootDirMock::new();
1342         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1343         let context = storage_files
1344             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1345             .unwrap();
1346         storage_files.stage_local_override(&context, "false").unwrap();
1347         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "false");
1348         let attribute = storage_files.get_flag_attribute(&context).unwrap();
1349         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) != 0);
1350     }
1351 
1352     #[test]
test_stage_and_apply_local_override()1353     fn test_stage_and_apply_local_override() {
1354         let container = ContainerMock::new();
1355         let root_dir = StorageRootDirMock::new();
1356         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1357         let context = storage_files
1358             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1359             .unwrap();
1360         storage_files.stage_and_apply_local_override(&context, "false").unwrap();
1361         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "false");
1362         assert_eq!(&storage_files.get_boot_flag_value(&context).unwrap(), "false");
1363         let attribute = storage_files.get_flag_attribute(&context).unwrap();
1364         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) != 0);
1365     }
1366 
1367     #[test]
test_apply_all_staged_overrides()1368     fn test_apply_all_staged_overrides() {
1369         let container = ContainerMock::new();
1370         let root_dir = StorageRootDirMock::new();
1371         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1372 
1373         let context_one = storage_files
1374             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1375             .unwrap();
1376         storage_files.stage_server_override(&context_one, "false").unwrap();
1377 
1378         let context_two = storage_files
1379             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1380             .unwrap();
1381         storage_files.stage_server_override(&context_two, "false").unwrap();
1382         storage_files.stage_local_override(&context_two, "true").unwrap();
1383 
1384         storage_files.apply_all_staged_overrides().unwrap();
1385 
1386         assert!(storage_files.storage_record.boot_flag_val.exists());
1387         assert!(storage_files.storage_record.boot_flag_info.exists());
1388 
1389         assert_eq!(storage_files.get_boot_flag_value(&context_one).unwrap(), "false");
1390         assert_eq!(storage_files.get_boot_flag_value(&context_two).unwrap(), "true");
1391     }
1392 
1393     #[test]
test_get_all_server_overrides()1394     fn test_get_all_server_overrides() {
1395         let container = ContainerMock::new();
1396         let root_dir = StorageRootDirMock::new();
1397         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1398         let mut context = storage_files
1399             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1400             .unwrap();
1401         storage_files.stage_server_override(&context, "false").unwrap();
1402         context = storage_files
1403             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1404             .unwrap();
1405         storage_files.stage_server_override(&context, "true").unwrap();
1406         let server_overrides = storage_files.get_all_server_overrides().unwrap();
1407         assert_eq!(server_overrides.len(), 2);
1408         assert_eq!(
1409             server_overrides[0],
1410             FlagValueSummary {
1411                 package_name: "com.android.aconfig.storage.test_1".to_string(),
1412                 flag_name: "enabled_rw".to_string(),
1413                 flag_value: "false".to_string(),
1414                 value_type: StoredFlagType::ReadWriteBoolean,
1415             }
1416         );
1417         assert_eq!(
1418             server_overrides[1],
1419             FlagValueSummary {
1420                 package_name: "com.android.aconfig.storage.test_2".to_string(),
1421                 flag_name: "disabled_rw".to_string(),
1422                 flag_value: "true".to_string(),
1423                 value_type: StoredFlagType::ReadWriteBoolean,
1424             }
1425         );
1426     }
1427 
1428     #[test]
test_get_all_local_overrides()1429     fn test_get_all_local_overrides() {
1430         let container = ContainerMock::new();
1431         let root_dir = StorageRootDirMock::new();
1432         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1433 
1434         let context_one = storage_files
1435             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1436             .unwrap();
1437         storage_files.stage_local_override(&context_one, "false").unwrap();
1438 
1439         let context_two = storage_files
1440             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1441             .unwrap();
1442         storage_files.stage_local_override(&context_two, "false").unwrap();
1443 
1444         let local_overrides = storage_files.get_all_local_overrides().unwrap();
1445         assert_eq!(local_overrides.len(), 2);
1446 
1447         let mut override_proto = ProtoFlagOverride::new();
1448         override_proto.set_package_name("com.android.aconfig.storage.test_1".to_string());
1449         override_proto.set_flag_name("enabled_rw".to_string());
1450         override_proto.set_flag_value("false".to_string());
1451         assert_eq!(local_overrides[0], override_proto);
1452 
1453         override_proto.set_package_name("com.android.aconfig.storage.test_2".to_string());
1454         override_proto.set_flag_name("disabled_rw".to_string());
1455         assert_eq!(local_overrides[1], override_proto);
1456     }
1457 
1458     #[test]
test_remove_local_override()1459     fn test_remove_local_override() {
1460         let container = ContainerMock::new();
1461         let root_dir = StorageRootDirMock::new();
1462         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1463         let context = storage_files
1464             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1465             .unwrap();
1466 
1467         assert!(storage_files.remove_local_override(&context).is_err());
1468         storage_files.stage_local_override(&context, "false").unwrap();
1469         storage_files.remove_local_override(&context).unwrap();
1470         assert_eq!(&storage_files.get_local_flag_value(&context).unwrap(), "");
1471         let attribute = storage_files.get_flag_attribute(&context).unwrap();
1472         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) == 0);
1473     }
1474 
1475     #[test]
test_remove_all_local_overrides()1476     fn test_remove_all_local_overrides() {
1477         let container = ContainerMock::new();
1478         let root_dir = StorageRootDirMock::new();
1479         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1480 
1481         let context_one = storage_files
1482             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1483             .unwrap();
1484         storage_files.stage_local_override(&context_one, "false").unwrap();
1485 
1486         let context_two = storage_files
1487             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1488             .unwrap();
1489         storage_files.stage_local_override(&context_two, "false").unwrap();
1490 
1491         let mut pb = read_pb_from_file::<ProtoLocalFlagOverrides>(
1492             &storage_files.storage_record.local_overrides,
1493         )
1494         .unwrap();
1495         assert_eq!(pb.overrides.len(), 2);
1496 
1497         storage_files.remove_all_local_overrides().unwrap();
1498 
1499         assert_eq!(&storage_files.get_local_flag_value(&context_one).unwrap(), "");
1500         let mut attribute = storage_files.get_flag_attribute(&context_one).unwrap();
1501         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) == 0);
1502 
1503         assert_eq!(&storage_files.get_local_flag_value(&context_two).unwrap(), "");
1504         attribute = storage_files.get_flag_attribute(&context_one).unwrap();
1505         assert!(attribute & (FlagInfoBit::HasLocalOverride as u8) == 0);
1506 
1507         pb = read_pb_from_file::<ProtoLocalFlagOverrides>(
1508             &storage_files.storage_record.local_overrides,
1509         )
1510         .unwrap();
1511         assert_eq!(pb.overrides.len(), 0);
1512     }
1513 
1514     #[test]
test_remove_persist_files()1515     fn test_remove_persist_files() {
1516         let container = ContainerMock::new();
1517         let root_dir = StorageRootDirMock::new();
1518         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1519         write_pb_to_file::<ProtoLocalFlagOverrides>(
1520             &ProtoLocalFlagOverrides::new(),
1521             &storage_files.storage_record.local_overrides,
1522         )
1523         .unwrap();
1524         assert!(storage_files.storage_record.persist_package_map.exists());
1525         assert!(storage_files.storage_record.persist_flag_map.exists());
1526         assert!(storage_files.storage_record.persist_flag_val.exists());
1527         assert!(storage_files.storage_record.persist_flag_info.exists());
1528         assert!(storage_files.storage_record.local_overrides.exists());
1529 
1530         storage_files.remove_persist_files().unwrap();
1531         assert!(!storage_files.storage_record.persist_package_map.exists());
1532         assert!(!storage_files.storage_record.persist_flag_map.exists());
1533         assert!(!storage_files.storage_record.persist_flag_val.exists());
1534         assert!(!storage_files.storage_record.persist_flag_info.exists());
1535         assert!(!storage_files.storage_record.local_overrides.exists());
1536     }
1537 
1538     #[test]
test_get_flag_snapshot()1539     fn test_get_flag_snapshot() {
1540         let container = ContainerMock::new();
1541         let root_dir = StorageRootDirMock::new();
1542         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1543 
1544         let mut flag = storage_files
1545             .get_flag_snapshot("com.android.aconfig.storage.test_1", "not_exist")
1546             .unwrap();
1547         assert_eq!(flag, None);
1548 
1549         let context = storage_files
1550             .get_package_flag_context("com.android.aconfig.storage.test_1", "disabled_rw")
1551             .unwrap();
1552         storage_files.stage_server_override(&context, "false").unwrap();
1553         storage_files.stage_local_override(&context, "true").unwrap();
1554         storage_files.apply_all_staged_overrides().unwrap();
1555 
1556         flag = storage_files
1557             .get_flag_snapshot("com.android.aconfig.storage.test_1", "disabled_rw")
1558             .unwrap();
1559 
1560         let expected_flag = FlagSnapshot {
1561             container: String::from("mockup"),
1562             package: String::from("com.android.aconfig.storage.test_1"),
1563             flag: String::from("disabled_rw"),
1564             server_value: String::from("false"),
1565             local_value: String::from("true"),
1566             boot_value: String::from("true"),
1567             default_value: String::from("false"),
1568             is_readwrite: true,
1569             has_server_override: true,
1570             has_local_override: true,
1571         };
1572 
1573         assert_eq!(flag, Some(expected_flag));
1574     }
1575 
1576     #[test]
test_list_flags_in_package()1577     fn test_list_flags_in_package() {
1578         let container = ContainerMock::new();
1579         let root_dir = StorageRootDirMock::new();
1580         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1581 
1582         let context_one = storage_files
1583             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1584             .unwrap();
1585         storage_files.stage_server_override(&context_one, "false").unwrap();
1586         let context_two = storage_files
1587             .get_package_flag_context("com.android.aconfig.storage.test_1", "disabled_rw")
1588             .unwrap();
1589         storage_files.stage_server_override(&context_two, "false").unwrap();
1590         storage_files.stage_local_override(&context_two, "true").unwrap();
1591         storage_files.apply_all_staged_overrides().unwrap();
1592 
1593         let flags =
1594             storage_files.list_flags_in_package("com.android.aconfig.storage.test_1").unwrap();
1595 
1596         let mut flag = FlagSnapshot {
1597             container: String::from("mockup"),
1598             package: String::from("com.android.aconfig.storage.test_1"),
1599             flag: String::from("disabled_rw"),
1600             server_value: String::from("false"),
1601             local_value: String::from("true"),
1602             boot_value: String::from("true"),
1603             default_value: String::from("false"),
1604             is_readwrite: true,
1605             has_server_override: true,
1606             has_local_override: true,
1607         };
1608         assert_eq!(flags[0], flag);
1609 
1610         flag = FlagSnapshot {
1611             container: String::from("mockup"),
1612             package: String::from("com.android.aconfig.storage.test_1"),
1613             flag: String::from("enabled_ro"),
1614             server_value: String::new(),
1615             local_value: String::new(),
1616             boot_value: String::from("true"),
1617             default_value: String::from("true"),
1618             is_readwrite: false,
1619             has_server_override: false,
1620             has_local_override: false,
1621         };
1622         assert_eq!(flags[1], flag);
1623 
1624         flag = FlagSnapshot {
1625             container: String::from("mockup"),
1626             package: String::from("com.android.aconfig.storage.test_1"),
1627             flag: String::from("enabled_rw"),
1628             server_value: String::from("false"),
1629             local_value: String::new(),
1630             boot_value: String::from("false"),
1631             default_value: String::from("true"),
1632             is_readwrite: true,
1633             has_server_override: true,
1634             has_local_override: false,
1635         };
1636         assert_eq!(flags[2], flag);
1637     }
1638 
1639     #[test]
test_list_all_flags()1640     fn test_list_all_flags() {
1641         let container = ContainerMock::new();
1642         let root_dir = StorageRootDirMock::new();
1643         let mut storage_files = create_mock_storage_files(&container, &root_dir);
1644 
1645         let context_one = storage_files
1646             .get_package_flag_context("com.android.aconfig.storage.test_1", "enabled_rw")
1647             .unwrap();
1648         storage_files.stage_server_override(&context_one, "false").unwrap();
1649         let context_two = storage_files
1650             .get_package_flag_context("com.android.aconfig.storage.test_2", "disabled_rw")
1651             .unwrap();
1652         storage_files.stage_server_override(&context_two, "false").unwrap();
1653         storage_files.stage_local_override(&context_two, "true").unwrap();
1654         storage_files.apply_all_staged_overrides().unwrap();
1655 
1656         let flags = storage_files.list_all_flags().unwrap();
1657         assert_eq!(flags.len(), 8);
1658 
1659         let mut flag = FlagSnapshot {
1660             container: String::from("mockup"),
1661             package: String::from("com.android.aconfig.storage.test_1"),
1662             flag: String::from("enabled_rw"),
1663             server_value: String::from("false"),
1664             local_value: String::new(),
1665             boot_value: String::from("false"),
1666             default_value: String::from("true"),
1667             is_readwrite: true,
1668             has_server_override: true,
1669             has_local_override: false,
1670         };
1671         assert_eq!(flags[2], flag);
1672 
1673         flag = FlagSnapshot {
1674             container: String::from("mockup"),
1675             package: String::from("com.android.aconfig.storage.test_2"),
1676             flag: String::from("disabled_rw"),
1677             server_value: String::from("false"),
1678             local_value: String::from("true"),
1679             boot_value: String::from("true"),
1680             default_value: String::from("false"),
1681             is_readwrite: true,
1682             has_server_override: true,
1683             has_local_override: true,
1684         };
1685         assert_eq!(flags[3], flag);
1686     }
1687 }
1688