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