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 super::*;
16 use crate::time::MockTimeApi;
17 use crate::time::TIME_API_MTX;
18
19 const BASE_RAW_MONOTONIC_TIME: Duration = Duration::from_secs(12345);
20 const BASE_RAW_BOOT_TIME: Duration = Duration::from_secs(67890);
21 const HOUR_IN_SECONDS: u64 = 3600;
22 const DEFAULT_MAX_IDLE_DURATION: Duration = Duration::from_secs(25 * HOUR_IN_SECONDS);
23
24 #[test]
test_suspend_monitor()25 fn test_suspend_monitor() {
26 let _m = TIME_API_MTX.lock();
27 let mock_monitonic = MockTimeApi::get_monotonic_time_context();
28 let mock_boot = MockTimeApi::get_boot_time_context();
29 mock_monitonic
30 .expect()
31 .times(1)
32 .return_const(MonotonicTime::from_duration(BASE_RAW_MONOTONIC_TIME));
33 mock_boot.expect().times(1).return_const(BootTime::from_duration(BASE_RAW_BOOT_TIME));
34 let mut suspend_monitor = SuspendMonitor::<MockTimeApi>::new();
35
36 // + 100s on monotonic clock
37 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
38 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(100),
39 ));
40 // + 300s on boottime clock
41 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(300));
42 mock_boot.expect().times(1).return_const(boot_now);
43 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::from_secs(200), boot_now));
44
45 // + 900s on monotonic clock
46 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
47 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(1000),
48 ));
49 // + 1000s on boottime clock
50 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(1300));
51 mock_boot.expect().times(1).return_const(boot_now);
52 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::from_secs(100), boot_now));
53 }
54
55 #[test]
test_suspend_monitor_negative_adjustment()56 fn test_suspend_monitor_negative_adjustment() {
57 let _m = TIME_API_MTX.lock();
58 let mock_monitonic = MockTimeApi::get_monotonic_time_context();
59 let mock_boot = MockTimeApi::get_boot_time_context();
60 mock_monitonic
61 .expect()
62 .times(1)
63 .return_const(MonotonicTime::from_duration(BASE_RAW_MONOTONIC_TIME));
64 mock_boot.expect().times(1).return_const(BootTime::from_duration(BASE_RAW_BOOT_TIME));
65 let mut suspend_monitor = SuspendMonitor::<MockTimeApi>::new();
66
67 // + 400s on monotonic clock
68 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
69 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(400),
70 ));
71 // + 100s on boottime clock
72 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(100));
73 mock_boot.expect().times(1).return_const(boot_now);
74 // 300s of negative adjustment is stored.
75 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::ZERO, boot_now));
76
77 // + 100s on monotonic clock
78 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
79 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(500),
80 ));
81 // + 1000s on boottime clock
82 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(1100));
83 mock_boot.expect().times(1).return_const(boot_now);
84 // suspend duration is 900s - 300s (negative adjustment from the last call)
85 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::from_secs(600), boot_now));
86
87 // + 100s on monotonic clock
88 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
89 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(600),
90 ));
91 // + 400s on boottime clock
92 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(1500));
93 mock_boot.expect().times(1).return_const(boot_now);
94 // suspend duration is 300s without negative adjustment
95 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::from_secs(300), boot_now));
96 }
97
98 #[test]
test_suspend_monitor_big_negative_adjustment()99 fn test_suspend_monitor_big_negative_adjustment() {
100 let _m = TIME_API_MTX.lock();
101 let mock_monitonic = MockTimeApi::get_monotonic_time_context();
102 let mock_boot = MockTimeApi::get_boot_time_context();
103 mock_monitonic
104 .expect()
105 .times(1)
106 .return_const(MonotonicTime::from_duration(BASE_RAW_MONOTONIC_TIME));
107 mock_boot.expect().times(1).return_const(BootTime::from_duration(BASE_RAW_BOOT_TIME));
108 let mut suspend_monitor = SuspendMonitor::<MockTimeApi>::new();
109
110 // + 400s on monotonic clock
111 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
112 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(400),
113 ));
114 // + 100s on boottime clock
115 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(100));
116 mock_boot.expect().times(1).return_const(boot_now);
117 // 300s of negative adjustment is stored.
118 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::ZERO, boot_now));
119
120 // + 100s on monotonic clock
121 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
122 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(500),
123 ));
124 // + 300s on boottime clock
125 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(400));
126 mock_boot.expect().times(1).return_const(boot_now);
127 // suspend duration is 200s is shorter than negative adjustment. 100s of negative adjustment is
128 // left.
129 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::ZERO, boot_now));
130
131 // + 100s on monotonic clock
132 mock_monitonic.expect().times(1).return_const(MonotonicTime::from_duration(
133 BASE_RAW_MONOTONIC_TIME + Duration::from_secs(600),
134 ));
135 // + 400s on boottime clock
136 let boot_now = BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(800));
137 mock_boot.expect().times(1).return_const(boot_now);
138 // suspend duration is 300s - 100s (negative adjustment).
139 assert_eq!(suspend_monitor.generate_suspend_duration(), (Duration::from_secs(200), boot_now));
140 }
141
142 #[test]
test_calculate_total_suspend_duration()143 fn test_calculate_total_suspend_duration() {
144 let mut history = SuspendHistory::new();
145
146 history.record_suspend_duration(
147 Duration::from_secs(2 * HOUR_IN_SECONDS),
148 BootTime::from_duration(BASE_RAW_BOOT_TIME),
149 DEFAULT_MAX_IDLE_DURATION,
150 );
151 history.record_suspend_duration(
152 Duration::from_secs(5 * HOUR_IN_SECONDS),
153 BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(7 * HOUR_IN_SECONDS)),
154 DEFAULT_MAX_IDLE_DURATION,
155 );
156 history.record_suspend_duration(
157 Duration::from_secs(2 * HOUR_IN_SECONDS),
158 BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(10 * HOUR_IN_SECONDS)),
159 DEFAULT_MAX_IDLE_DURATION,
160 );
161 history.record_suspend_duration(
162 Duration::from_secs(HOUR_IN_SECONDS),
163 BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(12 * HOUR_IN_SECONDS)),
164 DEFAULT_MAX_IDLE_DURATION,
165 );
166
167 assert_eq!(
168 history.calculate_total_suspend_duration(
169 Duration::from_secs(4 * HOUR_IN_SECONDS),
170 BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(13 * HOUR_IN_SECONDS))
171 ),
172 Duration::from_secs(8 * HOUR_IN_SECONDS)
173 );
174 }
175
176 #[test]
test_calculate_total_suspend_duration_empty()177 fn test_calculate_total_suspend_duration_empty() {
178 let history = SuspendHistory::new();
179
180 assert_eq!(
181 history.calculate_total_suspend_duration(
182 Duration::from_secs(4 * HOUR_IN_SECONDS),
183 BootTime::from_duration(BASE_RAW_BOOT_TIME + Duration::from_secs(13 * HOUR_IN_SECONDS))
184 ),
185 Duration::ZERO
186 );
187 }
188
189 #[test]
test_calculate_total_suspend_duration_negative_target()190 fn test_calculate_total_suspend_duration_negative_target() {
191 let history = SuspendHistory::new();
192
193 // now - target_duration is negative.
194 assert_eq!(
195 history.calculate_total_suspend_duration(
196 Duration::from_secs(4 * HOUR_IN_SECONDS),
197 BootTime::from_duration(Duration::from_secs(HOUR_IN_SECONDS))
198 ),
199 Duration::ZERO
200 );
201 }
202
203 #[test]
test_suspend_history_gc_entries()204 fn test_suspend_history_gc_entries() {
205 let max_idle_duration = Duration::from_secs(25 * HOUR_IN_SECONDS);
206 let base_raw_boot_time: Duration = Duration::ZERO;
207 let mut history = SuspendHistory::new();
208
209 assert_eq!(history.history.len(), 1);
210
211 // awake for 26 hours.
212 history.record_suspend_duration(
213 Duration::from_secs(HOUR_IN_SECONDS),
214 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(27 * HOUR_IN_SECONDS)),
215 max_idle_duration,
216 );
217 // Does not pop entry if there was only 1 entry.
218 assert_eq!(history.history.len(), 2);
219
220 // awake for 1 hour.
221 history.record_suspend_duration(
222 Duration::from_secs(HOUR_IN_SECONDS),
223 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(29 * HOUR_IN_SECONDS)),
224 max_idle_duration,
225 );
226 // The first entry is GC-ed.
227 assert_eq!(history.history.len(), 2);
228
229 // awake for 2 hour.
230 history.record_suspend_duration(
231 Duration::from_secs(HOUR_IN_SECONDS),
232 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(32 * HOUR_IN_SECONDS)),
233 max_idle_duration,
234 );
235 assert_eq!(history.history.len(), 3);
236
237 // awake for 10 hour.
238 history.record_suspend_duration(
239 Duration::from_secs(11 * HOUR_IN_SECONDS),
240 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(53 * HOUR_IN_SECONDS)),
241 max_idle_duration,
242 );
243 assert_eq!(history.history.len(), 4);
244
245 // awake for 20 hours.
246 history.record_suspend_duration(
247 Duration::from_secs(12 * HOUR_IN_SECONDS),
248 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(85 * HOUR_IN_SECONDS)),
249 max_idle_duration,
250 );
251 // The entries except last 2 entries are GC-ed.
252 assert_eq!(history.history.len(), 2);
253
254 assert_eq!(
255 history.calculate_total_suspend_duration(
256 Duration::from_secs(25 * HOUR_IN_SECONDS),
257 BootTime::from_duration(base_raw_boot_time + Duration::from_secs(85 * HOUR_IN_SECONDS))
258 ),
259 Duration::from_secs(23 * HOUR_IN_SECONDS)
260 );
261 }
262