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 //! mmd is a native daemon managing memory task:
16 //!
17 //! * zram
18 
19 mod properties;
20 mod service;
21 
22 use binder::BinderFeatures;
23 use log::error;
24 use log::info;
25 use log::warn;
26 use log::LevelFilter;
27 use mmd::zram::recompression::is_zram_recompression_activated;
28 use mmd::zram::recompression::ZramRecompression;
29 use mmd::zram::setup::activate_zram;
30 use mmd::zram::setup::is_zram_swap_activated;
31 use mmd::zram::setup::parse_zram_size_spec;
32 use mmd::zram::setup::SetupApiImpl;
33 use mmd::zram::stats::load_total_zram_size;
34 use mmd::zram::writeback::is_zram_writeback_activated;
35 use mmd::zram::writeback::ZramWriteback;
36 use mmd::zram::SysfsZramApiImpl;
37 use mmd_aidl_interface::aidl::android::os::IMmd::BnMmd;
38 use rustutils::system_properties;
39 
40 use crate::properties::BoolProp;
41 use crate::properties::StringProp;
42 
43 // In Android zram writeback file is always "/data/per_boot/zram_swap".
44 const ZRAM_WRITEBACK_FILE_PATH: &str = "/data/per_boot/zram_swap";
45 
setup_zram() -> anyhow::Result<()>46 fn setup_zram() -> anyhow::Result<()> {
47     let zram_activated = is_zram_swap_activated::<SetupApiImpl>()?;
48     if zram_activated {
49         info!("zram is already on, skipping zram setup");
50         return Ok(());
51     }
52 
53     let zram_size_spec = StringProp::ZramSize.get("50%");
54     let zram_size = parse_zram_size_spec(&zram_size_spec)?;
55     activate_zram::<SysfsZramApiImpl, SetupApiImpl>(zram_size)?;
56     Ok(())
57 }
58 
main()59 fn main() {
60     // "mmd --set-property" command copies the AConfig flag to "mmd.enabled_aconfig" system
61     // property as either "true" or "false".
62     // This is the workaround for init language which does not support AConfig integration.
63     // TODO: b/380365026 - Remove "--set-property" command when init language supports AConfig
64     // integration.
65     if std::env::args().nth(1).map(|s| &s == "--set-property").unwrap_or(false) {
66         let value = if mmd_flags::mmd_enabled() { "true" } else { "false" };
67         system_properties::write("mmd.enabled_aconfig", value).expect("set system property");
68         return;
69     }
70 
71     let _init_success = logger::init(
72         logger::Config::default().with_tag_on_device("mmd").with_max_level(LevelFilter::Trace),
73     );
74 
75     if !mmd_flags::mmd_enabled() {
76         // It is mmd.rc responsibility to start mmd process only if AConfig flag is enabled.
77         // This is a safe guard to ensure that mmd runs only when AConfig flag is enabled.
78         warn!("mmd is disabled");
79         return;
80     }
81 
82     if BoolProp::ZramEnabled.get(false) {
83         setup_zram().expect("zram setup");
84     }
85 
86     let total_zram_size = match load_total_zram_size::<SysfsZramApiImpl>() {
87         Ok(v) => v,
88         Err(e) => {
89             error!("failed to load total zram size: {e:?}");
90             std::process::exit(1);
91         }
92     };
93     let zram_writeback = if BoolProp::ZramWritebackEnabled.get(true) {
94         match load_zram_writeback_disk_size() {
95             Ok(Some(zram_writeback_disk_size)) => {
96                 info!("zram writeback is activated");
97                 Some(ZramWriteback::new(total_zram_size, zram_writeback_disk_size))
98             }
99             Ok(None) => {
100                 info!("zram writeback is not activated");
101                 None
102             }
103             Err(e) => {
104                 error!("failed to load zram writeback file size: {e:?}");
105                 None
106             }
107         }
108     } else {
109         info!("zram writeback is disabled");
110         None
111     };
112 
113     let zram_recompression = if BoolProp::ZramRecompressionEnabled.get(true) {
114         match is_zram_recompression_activated::<SysfsZramApiImpl>() {
115             Ok(is_activated) => {
116                 if is_activated {
117                     info!("zram recompression is activated");
118                     Some(ZramRecompression::new())
119                 } else {
120                     info!("zram recompression is not activated");
121                     None
122                 }
123             }
124             Err(e) => {
125                 error!("failed to check zram recompression is activated: {e:?}");
126                 None
127             }
128         }
129     } else {
130         info!("zram recompression is disabled");
131         None
132     };
133 
134     let mmd_service = service::MmdService::new(zram_writeback, zram_recompression);
135     let mmd_service_binder = BnMmd::new_binder(mmd_service, BinderFeatures::default());
136     binder::add_service("mmd", mmd_service_binder.as_binder()).expect("register service");
137 
138     info!("mmd started");
139 
140     binder::ProcessState::join_thread_pool();
141 }
142 
143 /// Loads the zram writeback disk size.
144 ///
145 /// If zram writeback is not enabled, this returns `Ok(None)`.
load_zram_writeback_disk_size() -> std::io::Result<Option<u64>>146 pub fn load_zram_writeback_disk_size() -> std::io::Result<Option<u64>> {
147     if is_zram_writeback_activated::<SysfsZramApiImpl>()? {
148         Ok(Some(std::fs::metadata(ZRAM_WRITEBACK_FILE_PATH)?.len()))
149     } else {
150         Ok(None)
151     }
152 }
153