// Copyright 2024, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! This module defines system properties used for mmd. //! //! System properties "mmd." are defined per OEM. //! //! Server configrations "persist.device_config.mmd_native." overrides the corresponding //! system properties for in-field experiment on a small population. use std::str::FromStr; use std::time::Duration; use flags_rust::GetServerConfigurableFlag; use log::error; use rustutils::system_properties; const SERVER_CONFIG_NAMESPACE: &str = "mmd_native"; fn generate_property_name(flag_name: &str) -> String { format!("mmd.{flag_name}") } /// bool system properties for mmd. /// /// clippy::enum_variant_names is allowed because we may add more properties. #[allow(clippy::enum_variant_names)] pub enum BoolProp { ZramEnabled, ZramWritebackEnabled, ZramWritebackHugeIdleEnabled, ZramWritebackIdleEnabled, ZramWritebackHugeEnabled, ZramRecompressionEnabled, ZramRecompressionHugeIdleEnabled, ZramRecompressionIdleEnabled, ZramRecompressionHugeEnabled, } impl BoolProp { fn flag_name(&self) -> &'static str { match self { Self::ZramEnabled => "zram.enabled", Self::ZramWritebackEnabled => "zram.writeback.enabled", Self::ZramWritebackHugeIdleEnabled => "zram.writeback.huge_idle.enabled", Self::ZramWritebackIdleEnabled => "zram.writeback.idle.enabled", Self::ZramWritebackHugeEnabled => "zram.writeback.huge.enabled", Self::ZramRecompressionEnabled => "zram.recompression.enabled", Self::ZramRecompressionHugeIdleEnabled => "zram.recompression.huge_idle.enabled", Self::ZramRecompressionIdleEnabled => "zram.recompression.idle.enabled", Self::ZramRecompressionHugeEnabled => "zram.recompression.huge.enabled", } } pub fn get(&self, default: bool) -> bool { if let Some(v) = read(self.flag_name()) { v } else { default } } } /// u64 system properties for mmd. /// /// clippy::enum_variant_names is allowed because we may add more properties. #[allow(clippy::enum_variant_names)] pub enum U64Prop { ZramWritebackMinBytes, ZramWritebackMaxBytes, ZramWritebackMaxBytesPerDay, ZramRecompressionThresholdMib, } impl U64Prop { fn flag_name(&self) -> &'static str { match self { Self::ZramWritebackMinBytes => "zram.writeback.min_bytes", Self::ZramWritebackMaxBytes => "zram.writeback.max_bytes", Self::ZramWritebackMaxBytesPerDay => "zram.writeback.max_bytes_per_day", Self::ZramRecompressionThresholdMib => "zram.recompression.threshold_mib", } } pub fn get(&self, default: u64) -> u64 { if let Some(v) = read(self.flag_name()) { v } else { default } } } /// Duration system properties for mmd in seconds. /// /// clippy::enum_variant_names is allowed because we may add more properties. #[allow(clippy::enum_variant_names)] pub enum SecondsProp { ZramWritebackBackoff, ZramWritebackMinIdle, ZramWritebackMaxIdle, ZramRecompressionBackoff, ZramRecompressionMinIdle, ZramRecompressionMaxIdle, } impl SecondsProp { fn flag_name(&self) -> &'static str { match self { Self::ZramWritebackBackoff => "zram.writeback.backoff_seconds", Self::ZramWritebackMinIdle => "zram.writeback.min_idle_seconds", Self::ZramWritebackMaxIdle => "zram.writeback.max_idle_seconds", Self::ZramRecompressionBackoff => "zram.recompression.backoff_seconds", Self::ZramRecompressionMinIdle => "zram.recompression.min_idle_seconds", Self::ZramRecompressionMaxIdle => "zram.recompression.max_idle_seconds", } } pub fn get(&self, default: Duration) -> Duration { if let Some(v) = read::(self.flag_name()) { Duration::from_secs(v) } else { default } } } /// String system properties for mmd. /// /// clippy::enum_variant_names is allowed because we may add more properties. #[allow(clippy::enum_variant_names)] pub enum StringProp { ZramSize, } impl StringProp { fn flag_name(&self) -> &'static str { match self { Self::ZramSize => "zram.size", } } pub fn get(&self, default: &str) -> String { read(self.flag_name()).unwrap_or_else(|| default.to_string()) } } fn read(flag_name: &str) -> Option { let value = GetServerConfigurableFlag(SERVER_CONFIG_NAMESPACE, flag_name, ""); if !value.is_empty() { if let Ok(v) = value.parse() { return Some(v); } error!("failed to parse server config flag: {flag_name}={value}"); } // fallback if server flag is not set or broken. let property_name = generate_property_name(flag_name); match system_properties::read(&property_name) { Ok(Some(v)) => { if let Ok(v) = v.parse() { return Some(v); } else { error!("failed to parse system property: {property_name}={v}"); } } Ok(None) => {} Err(e) => { error!("failed to read system property: {property_name} {e:?}"); } } None } #[cfg(test)] mod tests { use super::*; #[test] fn bool_prop_from_default() { // We can't test system properties directly. Just a unit test for // default value. assert!(BoolProp::ZramWritebackEnabled.get(true)); assert!(!BoolProp::ZramWritebackEnabled.get(false)); } #[test] fn u64_prop_from_default() { // We can't test system properties directly. Just a unit test for // default value. assert_eq!(U64Prop::ZramWritebackMinBytes.get(12345), 12345); } #[test] fn seconds_prop_from_default() { // We can't test system properties directly. Just a unit test for // default value. assert_eq!( SecondsProp::ZramWritebackBackoff.get(Duration::from_secs(12345)), Duration::from_secs(12345) ); } }