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 /// bool system properties for mmd.
36 ///
37 /// clippy::enum_variant_names is allowed because we may add more properties.
38 #[allow(clippy::enum_variant_names)]
39 pub enum BoolProp {
40 ZramEnabled,
41 ZramWritebackEnabled,
42 ZramWritebackHugeIdleEnabled,
43 ZramWritebackIdleEnabled,
44 ZramWritebackHugeEnabled,
45 ZramRecompressionEnabled,
46 ZramRecompressionHugeIdleEnabled,
47 ZramRecompressionIdleEnabled,
48 ZramRecompressionHugeEnabled,
49 }
50
51 impl BoolProp {
flag_name(&self) -> &'static str52 fn flag_name(&self) -> &'static str {
53 match self {
54 Self::ZramEnabled => "zram.enabled",
55 Self::ZramWritebackEnabled => "zram.writeback.enabled",
56 Self::ZramWritebackHugeIdleEnabled => "zram.writeback.huge_idle.enabled",
57 Self::ZramWritebackIdleEnabled => "zram.writeback.idle.enabled",
58 Self::ZramWritebackHugeEnabled => "zram.writeback.huge.enabled",
59 Self::ZramRecompressionEnabled => "zram.recompression.enabled",
60 Self::ZramRecompressionHugeIdleEnabled => "zram.recompression.huge_idle.enabled",
61 Self::ZramRecompressionIdleEnabled => "zram.recompression.idle.enabled",
62 Self::ZramRecompressionHugeEnabled => "zram.recompression.huge.enabled",
63 }
64 }
65
get(&self, default: bool) -> bool66 pub fn get(&self, default: bool) -> bool {
67 if let Some(v) = read(self.flag_name()) {
68 v
69 } else {
70 default
71 }
72 }
73 }
74
75 /// u64 system properties for mmd.
76 ///
77 /// clippy::enum_variant_names is allowed because we may add more properties.
78 #[allow(clippy::enum_variant_names)]
79 pub enum U64Prop {
80 ZramWritebackMinBytes,
81 ZramWritebackMaxBytes,
82 ZramWritebackMaxBytesPerDay,
83 ZramRecompressionThresholdMib,
84 }
85
86 impl U64Prop {
flag_name(&self) -> &'static str87 fn flag_name(&self) -> &'static str {
88 match self {
89 Self::ZramWritebackMinBytes => "zram.writeback.min_bytes",
90 Self::ZramWritebackMaxBytes => "zram.writeback.max_bytes",
91 Self::ZramWritebackMaxBytesPerDay => "zram.writeback.max_bytes_per_day",
92 Self::ZramRecompressionThresholdMib => "zram.recompression.threshold_mib",
93 }
94 }
95
get(&self, default: u64) -> u6496 pub fn get(&self, default: u64) -> u64 {
97 if let Some(v) = read(self.flag_name()) {
98 v
99 } else {
100 default
101 }
102 }
103 }
104
105 /// Duration system properties for mmd in seconds.
106 ///
107 /// clippy::enum_variant_names is allowed because we may add more properties.
108 #[allow(clippy::enum_variant_names)]
109 pub enum SecondsProp {
110 ZramWritebackBackoff,
111 ZramWritebackMinIdle,
112 ZramWritebackMaxIdle,
113 ZramRecompressionBackoff,
114 ZramRecompressionMinIdle,
115 ZramRecompressionMaxIdle,
116 }
117
118 impl SecondsProp {
flag_name(&self) -> &'static str119 fn flag_name(&self) -> &'static str {
120 match self {
121 Self::ZramWritebackBackoff => "zram.writeback.backoff_seconds",
122 Self::ZramWritebackMinIdle => "zram.writeback.min_idle_seconds",
123 Self::ZramWritebackMaxIdle => "zram.writeback.max_idle_seconds",
124 Self::ZramRecompressionBackoff => "zram.recompression.backoff_seconds",
125 Self::ZramRecompressionMinIdle => "zram.recompression.min_idle_seconds",
126 Self::ZramRecompressionMaxIdle => "zram.recompression.max_idle_seconds",
127 }
128 }
129
get(&self, default: Duration) -> Duration130 pub fn get(&self, default: Duration) -> Duration {
131 if let Some(v) = read::<u64>(self.flag_name()) {
132 Duration::from_secs(v)
133 } else {
134 default
135 }
136 }
137 }
138
139 /// String system properties for mmd.
140 ///
141 /// clippy::enum_variant_names is allowed because we may add more properties.
142 #[allow(clippy::enum_variant_names)]
143 pub enum StringProp {
144 ZramSize,
145 }
146
147 impl StringProp {
flag_name(&self) -> &'static str148 fn flag_name(&self) -> &'static str {
149 match self {
150 Self::ZramSize => "zram.size",
151 }
152 }
153
get(&self, default: &str) -> String154 pub fn get(&self, default: &str) -> String {
155 read(self.flag_name()).unwrap_or_else(|| default.to_string())
156 }
157 }
158
read<T: FromStr>(flag_name: &str) -> Option<T>159 fn read<T: FromStr>(flag_name: &str) -> Option<T> {
160 let value = GetServerConfigurableFlag(SERVER_CONFIG_NAMESPACE, flag_name, "");
161 if !value.is_empty() {
162 if let Ok(v) = value.parse() {
163 return Some(v);
164 }
165 error!("failed to parse server config flag: {flag_name}={value}");
166 }
167
168 // fallback if server flag is not set or broken.
169 let property_name = generate_property_name(flag_name);
170 match system_properties::read(&property_name) {
171 Ok(Some(v)) => {
172 if let Ok(v) = v.parse() {
173 return Some(v);
174 } else {
175 error!("failed to parse system property: {property_name}={v}");
176 }
177 }
178 Ok(None) => {}
179 Err(e) => {
180 error!("failed to read system property: {property_name} {e:?}");
181 }
182 }
183
184 None
185 }
186
187 #[cfg(test)]
188 mod tests {
189 use super::*;
190
191 #[test]
bool_prop_from_default()192 fn bool_prop_from_default() {
193 // We can't test system properties directly. Just a unit test for
194 // default value.
195 assert!(BoolProp::ZramWritebackEnabled.get(true));
196 assert!(!BoolProp::ZramWritebackEnabled.get(false));
197 }
198
199 #[test]
u64_prop_from_default()200 fn u64_prop_from_default() {
201 // We can't test system properties directly. Just a unit test for
202 // default value.
203 assert_eq!(U64Prop::ZramWritebackMinBytes.get(12345), 12345);
204 }
205
206 #[test]
seconds_prop_from_default()207 fn seconds_prop_from_default() {
208 // We can't test system properties directly. Just a unit test for
209 // default value.
210 assert_eq!(
211 SecondsProp::ZramWritebackBackoff.get(Duration::from_secs(12345)),
212 Duration::from_secs(12345)
213 );
214 }
215 }
216