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