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