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