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 use std::sync::Mutex;
16 use std::time::Instant;
17
18 use anyhow::Context;
19 use binder::Interface;
20 use binder::Result as BinderResult;
21 use log::error;
22 use mmd_aidl_interface::aidl::android::os::IMmd::IMmd;
23
24 use mmd::os::MeminfoApiImpl;
25 use mmd::zram::recompression::Error as ZramRecompressionError;
26 use mmd::zram::recompression::ZramRecompression;
27 use mmd::zram::writeback::Error as ZramWritebackError;
28 use mmd::zram::writeback::ZramWriteback;
29 use mmd::zram::SysfsZramApiImpl;
30
31 use crate::properties::BoolProp;
32 use crate::properties::SecondsProp;
33 use crate::properties::U64Prop;
34
35 struct ZramContext {
36 zram_writeback: Option<ZramWriteback>,
37 zram_recompression: Option<ZramRecompression>,
38 }
39
40 pub struct MmdService {
41 ctx: Mutex<ZramContext>,
42 }
43
44 impl MmdService {
new( zram_writeback: Option<ZramWriteback>, zram_recompression: Option<ZramRecompression>, ) -> Self45 pub fn new(
46 zram_writeback: Option<ZramWriteback>,
47 zram_recompression: Option<ZramRecompression>,
48 ) -> Self {
49 Self { ctx: Mutex::new(ZramContext { zram_writeback, zram_recompression }) }
50 }
51 }
52
53 impl Interface for MmdService {}
54
55 impl IMmd for MmdService {
doZramMaintenance(&self) -> BinderResult<()>56 fn doZramMaintenance(&self) -> BinderResult<()> {
57 let mut ctx = self.ctx.lock().expect("mmd aborts on panics");
58
59 // Execute recompression before writeback.
60 if let Some(zram_recompression) = ctx.zram_recompression.as_mut() {
61 let params = load_zram_recompression_params();
62 match zram_recompression
63 .mark_and_recompress::<SysfsZramApiImpl, MeminfoApiImpl>(¶ms, Instant::now())
64 {
65 Ok(_) | Err(ZramRecompressionError::BackoffTime) => {}
66 Err(e) => error!("failed to zram recompress: {e:?}"),
67 }
68 }
69
70 if let Some(zram_writeback) = ctx.zram_writeback.as_mut() {
71 let params = load_zram_writeback_params();
72 let stats = match load_zram_writeback_stats() {
73 Ok(v) => v,
74 Err(e) => {
75 error!("failed to load zram writeback stats: {e:?}");
76 return Ok(());
77 }
78 };
79 match zram_writeback.mark_and_flush_pages::<SysfsZramApiImpl, MeminfoApiImpl>(
80 ¶ms,
81 &stats,
82 Instant::now(),
83 ) {
84 Ok(_) | Err(ZramWritebackError::BackoffTime) | Err(ZramWritebackError::Limit) => {}
85 Err(e) => error!("failed to zram writeback: {e:?}"),
86 }
87 }
88
89 Ok(())
90 }
91 }
92
load_zram_writeback_params() -> mmd::zram::writeback::Params93 fn load_zram_writeback_params() -> mmd::zram::writeback::Params {
94 let mut params = mmd::zram::writeback::Params::default();
95 params.backoff_duration = SecondsProp::ZramWritebackBackoff.get(params.backoff_duration);
96 params.min_idle = SecondsProp::ZramWritebackMinIdle.get(params.min_idle);
97 params.max_idle = SecondsProp::ZramWritebackMaxIdle.get(params.max_idle);
98 params.huge_idle = BoolProp::ZramWritebackHugeIdleEnabled.get(params.huge_idle);
99 params.idle = BoolProp::ZramWritebackIdleEnabled.get(params.idle);
100 params.huge = BoolProp::ZramWritebackHugeEnabled.get(params.huge);
101 params.min_bytes = U64Prop::ZramWritebackMinBytes.get(params.min_bytes);
102 params.max_bytes = U64Prop::ZramWritebackMaxBytes.get(params.max_bytes);
103 params.max_bytes_per_day = U64Prop::ZramWritebackMaxBytesPerDay.get(params.max_bytes_per_day);
104 params
105 }
106
load_zram_writeback_stats() -> anyhow::Result<mmd::zram::writeback::Stats>107 fn load_zram_writeback_stats() -> anyhow::Result<mmd::zram::writeback::Stats> {
108 let mm_stat =
109 mmd::zram::stats::ZramMmStat::load::<SysfsZramApiImpl>().context("load mm_stat")?;
110 let bd_stat =
111 mmd::zram::stats::ZramBdStat::load::<SysfsZramApiImpl>().context("load bd_stat")?;
112 Ok(mmd::zram::writeback::Stats {
113 orig_data_size: mm_stat.orig_data_size,
114 current_writeback_pages: bd_stat.bd_count_pages,
115 })
116 }
117
load_zram_recompression_params() -> mmd::zram::recompression::Params118 fn load_zram_recompression_params() -> mmd::zram::recompression::Params {
119 let mut params = mmd::zram::recompression::Params::default();
120 params.backoff_duration = SecondsProp::ZramRecompressionBackoff.get(params.backoff_duration);
121 params.min_idle = SecondsProp::ZramRecompressionMinIdle.get(params.min_idle);
122 params.max_idle = SecondsProp::ZramRecompressionMaxIdle.get(params.max_idle);
123 params.huge_idle = BoolProp::ZramRecompressionHugeIdleEnabled.get(params.huge_idle);
124 params.idle = BoolProp::ZramRecompressionIdleEnabled.get(params.idle);
125 params.huge = BoolProp::ZramRecompressionHugeEnabled.get(params.huge);
126 params.max_mib = U64Prop::ZramRecompressionThresholdMib.get(params.max_mib);
127 params
128 }
129