Load system properties for mmd
mmd uses system properties in "mmd." namespace. mmd also uses server
configurations under "persist.device_config.mmd_native." namespace.
Bug: 375431994
Test: manual
Change-Id: Ieb9ddf77ee68a71a2cfad6fde9212ee14a258ae7
diff --git a/Android.bp b/Android.bp
index 7c67c9b..369fbe4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10,6 +10,7 @@
rustlibs: [
"libanyhow",
"libbinder_rs",
+ "libflags_rust",
"liblogger",
"liblog_rust",
"libmmd",
diff --git a/src/main.rs b/src/main.rs
index 06f5113..374beb6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,6 +16,7 @@
//!
//! * zram
+mod properties;
mod service;
use std::time::Duration;
@@ -34,6 +35,8 @@
use mmd_aidl_interface::aidl::android::os::IMmd::BnMmd;
use rustutils::system_properties;
+use crate::properties::BoolProp;
+
// In Android zram writeback file is always "/data/per_boot/zram_swap".
const ZRAM_WRITEBACK_FILE_PATH: &str = "/data/per_boot/zram_swap";
@@ -71,35 +74,45 @@
std::process::exit(1);
}
};
- let zram_writeback = match load_zram_writeback_disk_size() {
- Ok(Some(zram_writeback_disk_size)) => {
- info!("zram writeback is enabled");
- Some(ZramWriteback::new(total_zram_size, zram_writeback_disk_size))
- }
- Ok(None) => {
- info!("zram writeback is disabled");
- None
- }
- Err(e) => {
- error!("failed to load zram writeback file size: {e:?}");
- None
- }
- };
-
- let zram_recompression = match is_zram_recompression_activated::<SysfsZramApiImpl>() {
- Ok(is_activated) => {
- if is_activated {
- info!("zram recompression is enabled");
- Some(ZramRecompression::new())
- } else {
- info!("zram recompression is disabled");
+ let zram_writeback = if BoolProp::ZramWritebackEnabled.get(true) {
+ match load_zram_writeback_disk_size() {
+ Ok(Some(zram_writeback_disk_size)) => {
+ info!("zram writeback is activated");
+ Some(ZramWriteback::new(total_zram_size, zram_writeback_disk_size))
+ }
+ Ok(None) => {
+ info!("zram writeback is not activated");
+ None
+ }
+ Err(e) => {
+ error!("failed to load zram writeback file size: {e:?}");
None
}
}
- Err(e) => {
- error!("failed to check zram recompression is activated: {e:?}");
- None
+ } else {
+ info!("zram writeback is disabled");
+ None
+ };
+
+ let zram_recompression = if BoolProp::ZramRecompressionEnabled.get(true) {
+ match is_zram_recompression_activated::<SysfsZramApiImpl>() {
+ Ok(is_activated) => {
+ if is_activated {
+ info!("zram recompression is activated");
+ Some(ZramRecompression::new())
+ } else {
+ info!("zram recompression is not activated");
+ None
+ }
+ }
+ Err(e) => {
+ error!("failed to check zram recompression is activated: {e:?}");
+ None
+ }
}
+ } else {
+ info!("zram recompression is disabled");
+ None
};
let mmd_service = service::MmdService::new(zram_writeback, zram_recompression);
@@ -121,11 +134,3 @@
Ok(None)
}
}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
- }
-}
diff --git a/src/properties.rs b/src/properties.rs
new file mode 100644
index 0000000..435b1b2
--- /dev/null
+++ b/src/properties.rs
@@ -0,0 +1,193 @@
+// 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.<flag_name>" are defined per OEM.
+//!
+//! Server configrations "persist.device_config.mmd_native.<flag_name>" 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 {
+ ZramWritebackEnabled,
+ ZramWritebackHugeIdleEnabled,
+ ZramWritebackIdleEnabled,
+ ZramWritebackHugeEnabled,
+ ZramRecompressionEnabled,
+ ZramRecompressionHugeIdleEnabled,
+ ZramRecompressionIdleEnabled,
+ ZramRecompressionHugeEnabled,
+}
+
+impl BoolProp {
+ fn flag_name(&self) -> &'static str {
+ match self {
+ 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::<u64>(self.flag_name()) {
+ Duration::from_secs(v)
+ } else {
+ default
+ }
+ }
+}
+
+fn read<T: FromStr>(flag_name: &str) -> Option<T> {
+ 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)
+ );
+ }
+}
diff --git a/src/service.rs b/src/service.rs
index be3913f..c7d67fc 100644
--- a/src/service.rs
+++ b/src/service.rs
@@ -28,6 +28,10 @@
use mmd::zram::writeback::ZramWriteback;
use mmd::zram::SysfsZramApiImpl;
+use crate::properties::BoolProp;
+use crate::properties::SecondsProp;
+use crate::properties::U64Prop;
+
struct ZramContext {
zram_writeback: Option<ZramWriteback>,
zram_recompression: Option<ZramRecompression>,
@@ -87,8 +91,17 @@
}
fn load_zram_writeback_params() -> mmd::zram::writeback::Params {
- // TODO: load params from system properties.
- mmd::zram::writeback::Params::default()
+ let mut params = mmd::zram::writeback::Params::default();
+ params.backoff_duration = SecondsProp::ZramWritebackBackoff.get(params.backoff_duration);
+ params.min_idle = SecondsProp::ZramWritebackMinIdle.get(params.min_idle);
+ params.max_idle = SecondsProp::ZramWritebackMaxIdle.get(params.max_idle);
+ params.huge_idle = BoolProp::ZramWritebackHugeIdleEnabled.get(params.huge_idle);
+ params.idle = BoolProp::ZramWritebackIdleEnabled.get(params.idle);
+ params.huge = BoolProp::ZramWritebackHugeEnabled.get(params.huge);
+ params.min_bytes = U64Prop::ZramWritebackMinBytes.get(params.min_bytes);
+ params.max_bytes = U64Prop::ZramWritebackMaxBytes.get(params.max_bytes);
+ params.max_bytes_per_day = U64Prop::ZramWritebackMaxBytesPerDay.get(params.max_bytes_per_day);
+ params
}
fn load_zram_writeback_stats() -> anyhow::Result<mmd::zram::writeback::Stats> {
@@ -103,6 +116,13 @@
}
fn load_zram_recompression_params() -> mmd::zram::recompression::Params {
- // TODO: load params from system properties.
- mmd::zram::recompression::Params::default()
+ let mut params = mmd::zram::recompression::Params::default();
+ params.backoff_duration = SecondsProp::ZramRecompressionBackoff.get(params.backoff_duration);
+ params.min_idle = SecondsProp::ZramRecompressionMinIdle.get(params.min_idle);
+ params.max_idle = SecondsProp::ZramRecompressionMaxIdle.get(params.max_idle);
+ params.huge_idle = BoolProp::ZramRecompressionHugeIdleEnabled.get(params.huge_idle);
+ params.idle = BoolProp::ZramRecompressionIdleEnabled.get(params.idle);
+ params.huge = BoolProp::ZramRecompressionHugeEnabled.get(params.huge);
+ params.max_mib = U64Prop::ZramRecompressionThresholdMib.get(params.max_mib);
+ params
}