• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! The time library of libmmd.
16 //!
17 //! libmmd cares about the type of clock is boot time or monotonic time to calculate suspend
18 //! duration of the system at `crate::suspend_history` module.
19 //!
20 //! In Android [std::time::Instant] is based on boot time clock unlike the official rust standard
21 //! library is based on monotonic clock. libmmd defines its own [BootTime] and [MonotonicTime]
22 //! explicitly and refrain from depending on [std::time::Instant].
23 //!
24 //! https://android.googlesource.com/toolchain/android_rust/+/refs/heads/main/patches/longterm/rustc-0018-Switch-Instant-to-use-CLOCK_BOOTTIME.patch
25 
26 use std::time::Duration;
27 
28 use nix::time::clock_gettime;
29 
30 /// [TimeApi] is the mockable interface of clock_gettime(3).
31 #[cfg_attr(test, mockall::automock)]
32 pub trait TimeApi {
33     /// Get the current monotonic time.
get_monotonic_time() -> MonotonicTime34     fn get_monotonic_time() -> MonotonicTime;
35     /// Get the current boot time.
get_boot_time() -> BootTime36     fn get_boot_time() -> BootTime;
37 }
38 
39 /// The implementation of [TimeApi].
40 pub struct TimeApiImpl;
41 
42 impl TimeApi for TimeApiImpl {
get_monotonic_time() -> MonotonicTime43     fn get_monotonic_time() -> MonotonicTime {
44         clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC)
45             .map(|t| MonotonicTime(t.into()))
46             .expect("clock_gettime(CLOCK_MONOTONIC) never fails")
47     }
48 
get_boot_time() -> BootTime49     fn get_boot_time() -> BootTime {
50         clock_gettime(nix::time::ClockId::CLOCK_BOOTTIME)
51             .map(|t| BootTime(t.into()))
52             .expect("clock_gettime(CLOCK_BOOTTIME) never fails")
53     }
54 }
55 
56 /// Mutex to synchronize tests using [MockTimeApi].
57 ///
58 /// mockall for static functions requires synchronization.
59 ///
60 /// https://docs.rs/mockall/latest/mockall/#static-methods
61 #[cfg(test)]
62 pub static TIME_API_MTX: std::sync::Mutex<()> = std::sync::Mutex::new(());
63 
64 /// The representation of monotonic time.
65 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
66 pub struct MonotonicTime(Duration);
67 
68 impl MonotonicTime {
69     /// This returns the durtion elapsed from `earlier` time.
70     ///
71     /// This returns zero duration if `earlier` is later than this.
saturating_duration_since(&self, earlier: Self) -> Duration72     pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
73         self.0.saturating_sub(earlier.0)
74     }
75 
76     /// Creates [MonotonicTime] from [Duration].
77     ///
78     /// This will be mainly used for testing purpose. Otherwise, [TimeApiImpl::get_monotonic_time]
79     /// is recommended.
from_duration(value: Duration) -> Self80     pub const fn from_duration(value: Duration) -> Self {
81         Self(value)
82     }
83 }
84 
85 /// The representation of boot time.
86 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
87 pub struct BootTime(Duration);
88 
89 impl BootTime {
90     /// The zero boot time.
91     pub const ZERO: BootTime = BootTime(Duration::ZERO);
92 
93     /// This returns the durtion elapsed from `earlier` time.
94     ///
95     /// This returns zero duration if `earlier` is later than this.
saturating_duration_since(&self, earlier: Self) -> Duration96     pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
97         self.0.saturating_sub(earlier.0)
98     }
99 
100     /// Returns the `BootTime` added by the duration.
101     ///
102     /// Returns `None` if overflow occurs.
checked_add(&self, duration: Duration) -> Option<Self>103     pub fn checked_add(&self, duration: Duration) -> Option<Self> {
104         self.0.checked_add(duration).map(Self)
105     }
106 
107     /// Returns the `BootTime` subtracted by the duration.
108     ///
109     /// Returns `None` if the duration is bigger than the boot time.
checked_sub(&self, duration: Duration) -> Option<Self>110     pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
111         self.0.checked_sub(duration).map(Self)
112     }
113 
114     /// Creates [BootTime] from [Duration].
115     ///
116     /// This will be mainly used for testing purpose. Otherwise, [TimeApiImpl::get_boot_time] is
117     /// recommended.
from_duration(value: Duration) -> Self118     pub const fn from_duration(value: Duration) -> Self {
119         Self(value)
120     }
121 }
122