• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This module defines system properties used for mmd.
16 //!
17 //! System properties "mmd.<flag_name>" are defined per OEM.
18 //!
19 //! Server configrations "persist.device_config.mmd_native.<flag_name>" overrides the corresponding
20 //! system properties for in-field experiment on a small population.
21 
22 use std::str::FromStr;
23 use std::time::Duration;
24 
25 use flags_rust::GetServerConfigurableFlag;
26 use log::error;
27 use rustutils::system_properties;
28 
29 const SERVER_CONFIG_NAMESPACE: &str = "mmd_native";
30 
generate_property_name(flag_name: &str) -> String31 fn generate_property_name(flag_name: &str) -> String {
32     format!("mmd.{flag_name}")
33 }
34 
35 /// Returns whether mmd manages zram or not.
36 ///
37 /// If this is false, zram is managed by other system (e.g. swapon_all) or zram
38 /// is disabled on the device.
39 ///
40 /// Mmd checks mmd.zram.enabled without the overlay of DeviceConfig because we
41 /// don't plan any experiments toggling zram enabled/disabled. Taking
42 /// DeviceConfig into account rather makes the logic to switch zram management
43 /// system complex.
is_zram_enabled() -> bool44 pub fn is_zram_enabled() -> bool {
45     match mmdproperties::mmdproperties::mmd_zram_enabled() {
46         Ok(v) => v.unwrap_or(false),
47         Err(e) => {
48             error!("failed to load mmd.zram.enabled: {e:?}");
49             false
50         }
51     }
52 }
53 
54 /// bool system properties for mmd.
55 ///
56 /// clippy::enum_variant_names is allowed because we may add more properties.
57 #[allow(clippy::enum_variant_names)]
58 pub enum BoolProp {
59     ZramWritebackEnabled,
60     ZramWritebackHugeIdleEnabled,
61     ZramWritebackIdleEnabled,
62     ZramWritebackHugeEnabled,
63     ZramRecompressionEnabled,
64     ZramRecompressionHugeIdleEnabled,
65     ZramRecompressionIdleEnabled,
66     ZramRecompressionHugeEnabled,
67 }
68 
69 impl BoolProp {
flag_name(&self) -> &'static str70     fn flag_name(&self) -> &'static str {
71         match self {
72             Self::ZramWritebackEnabled => "zram.writeback.enabled",
73             Self::ZramWritebackHugeIdleEnabled => "zram.writeback.huge_idle.enabled",
74             Self::ZramWritebackIdleEnabled => "zram.writeback.idle.enabled",
75             Self::ZramWritebackHugeEnabled => "zram.writeback.huge.enabled",
76             Self::ZramRecompressionEnabled => "zram.recompression.enabled",
77             Self::ZramRecompressionHugeIdleEnabled => "zram.recompression.huge_idle.enabled",
78             Self::ZramRecompressionIdleEnabled => "zram.recompression.idle.enabled",
79             Self::ZramRecompressionHugeEnabled => "zram.recompression.huge.enabled",
80         }
81     }
82 
get(&self, default: bool) -> bool83     pub fn get(&self, default: bool) -> bool {
84         if let Some(v) = read(self.flag_name()) {
85             v
86         } else {
87             default
88         }
89     }
90 }
91 
92 /// u64 system properties for mmd.
93 ///
94 /// clippy::enum_variant_names is allowed because we may add more properties.
95 #[allow(clippy::enum_variant_names)]
96 pub enum U64Prop {
97     ZramWritebackMinBytes,
98     ZramWritebackMaxBytes,
99     ZramWritebackMaxBytesPerDay,
100     ZramRecompressionThresholdBytes,
101     ZramWritebackMinFreeSpaceMib,
102 }
103 
104 impl U64Prop {
flag_name(&self) -> &'static str105     fn flag_name(&self) -> &'static str {
106         match self {
107             Self::ZramWritebackMinBytes => "zram.writeback.min_bytes",
108             Self::ZramWritebackMaxBytes => "zram.writeback.max_bytes",
109             Self::ZramWritebackMaxBytesPerDay => "zram.writeback.max_bytes_per_day",
110             Self::ZramRecompressionThresholdBytes => "zram.recompression.threshold_bytes",
111             Self::ZramWritebackMinFreeSpaceMib => "zram.writeback.min_free_space_mib",
112         }
113     }
114 
get(&self, default: u64) -> u64115     pub fn get(&self, default: u64) -> u64 {
116         if let Some(v) = read(self.flag_name()) {
117             v
118         } else {
119             default
120         }
121     }
122 }
123 
124 /// Duration system properties for mmd in seconds.
125 ///
126 /// clippy::enum_variant_names is allowed because we may add more properties.
127 #[allow(clippy::enum_variant_names)]
128 pub enum SecondsProp {
129     ZramWritebackBackoff,
130     ZramWritebackMinIdle,
131     ZramWritebackMaxIdle,
132     ZramRecompressionBackoff,
133     ZramRecompressionMinIdle,
134     ZramRecompressionMaxIdle,
135 }
136 
137 impl SecondsProp {
flag_name(&self) -> &'static str138     fn flag_name(&self) -> &'static str {
139         match self {
140             Self::ZramWritebackBackoff => "zram.writeback.backoff_seconds",
141             Self::ZramWritebackMinIdle => "zram.writeback.min_idle_seconds",
142             Self::ZramWritebackMaxIdle => "zram.writeback.max_idle_seconds",
143             Self::ZramRecompressionBackoff => "zram.recompression.backoff_seconds",
144             Self::ZramRecompressionMinIdle => "zram.recompression.min_idle_seconds",
145             Self::ZramRecompressionMaxIdle => "zram.recompression.max_idle_seconds",
146         }
147     }
148 
get(&self, default: Duration) -> Duration149     pub fn get(&self, default: Duration) -> Duration {
150         if let Some(v) = read::<u64>(self.flag_name()) {
151             Duration::from_secs(v)
152         } else {
153             default
154         }
155     }
156 }
157 
158 /// String system properties for mmd.
159 ///
160 /// clippy::enum_variant_names is allowed because we may add more properties.
161 #[allow(clippy::enum_variant_names)]
162 pub enum StringProp {
163     ZramSize,
164     ZramCompAlgorithm,
165     ZramWritebackDeviceSize,
166     ZramRecompressionAlgorithm,
167 }
168 
169 impl StringProp {
flag_name(&self) -> &'static str170     fn flag_name(&self) -> &'static str {
171         match self {
172             Self::ZramSize => "zram.size",
173             Self::ZramCompAlgorithm => "zram.comp_algorithm",
174             Self::ZramWritebackDeviceSize => "zram.writeback.device_size",
175             Self::ZramRecompressionAlgorithm => "zram.recompression.algorithm",
176         }
177     }
178 
get<T: ToString + ?Sized>(&self, default: &T) -> String179     pub fn get<T: ToString + ?Sized>(&self, default: &T) -> String {
180         read(self.flag_name()).unwrap_or_else(|| default.to_string())
181     }
182 }
183 
read<T: FromStr>(flag_name: &str) -> Option<T>184 fn read<T: FromStr>(flag_name: &str) -> Option<T> {
185     let value = GetServerConfigurableFlag(SERVER_CONFIG_NAMESPACE, flag_name, "");
186     if !value.is_empty() {
187         if let Ok(v) = value.parse() {
188             return Some(v);
189         }
190         error!("failed to parse server config flag: {flag_name}={value}");
191     }
192 
193     // fallback if server flag is not set or broken.
194     let property_name = generate_property_name(flag_name);
195     match system_properties::read(&property_name) {
196         Ok(Some(v)) => {
197             if let Ok(v) = v.parse() {
198                 return Some(v);
199             } else {
200                 error!("failed to parse system property: {property_name}={v}");
201             }
202         }
203         Ok(None) => {}
204         Err(e) => {
205             error!("failed to read system property: {property_name} {e:?}");
206         }
207     }
208 
209     None
210 }
211 
212 #[cfg(test)]
213 mod tests {
214     use super::*;
215 
216     #[test]
bool_prop_from_default()217     fn bool_prop_from_default() {
218         // We can't test system properties directly. Just a unit test for
219         // default value.
220         assert!(BoolProp::ZramWritebackEnabled.get(true));
221         assert!(!BoolProp::ZramWritebackEnabled.get(false));
222     }
223 
224     #[test]
u64_prop_from_default()225     fn u64_prop_from_default() {
226         // We can't test system properties directly. Just a unit test for
227         // default value.
228         assert_eq!(U64Prop::ZramWritebackMinBytes.get(12345), 12345);
229     }
230 
231     #[test]
seconds_prop_from_default()232     fn seconds_prop_from_default() {
233         // We can't test system properties directly. Just a unit test for
234         // default value.
235         assert_eq!(
236             SecondsProp::ZramWritebackBackoff.get(Duration::from_secs(12345)),
237             Duration::from_secs(12345)
238         );
239     }
240 
241     #[test]
string_prop_from_default()242     fn string_prop_from_default() {
243         // We can't test system properties directly. Just a unit test for
244         // default value.
245         assert_eq!(StringProp::ZramSize.get("1%"), "1%");
246         assert_eq!(StringProp::ZramSize.get(&1024), "1024");
247     }
248 }
249