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>(&params, 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                 &params,
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