• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
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 
16 #include "timer_info.h"
17 
18 #include <cinttypes>
19 #include <memory>
20 
21 namespace OHOS {
22 namespace MiscServices {
23 using namespace std::chrono;
24 static constexpr uint32_t HALF_SECEND = 2;
25 const auto INTERVAL_HOUR = hours(1);
26 const auto INTERVAL_HALF_DAY = hours(12);
27 constexpr int64_t MAX_MILLISECOND = std::numeric_limits<int64_t>::max() / 1000000;
28 const auto MIN_INTERVAL_ONE_SECONDS = seconds(1);
29 const auto MAX_INTERVAL = hours(24 * 365);
30 const auto MIN_FUZZABLE_INTERVAL = milliseconds(10000);
31 constexpr float_t BATCH_WINDOW_COE = 0.75;
32 const auto ZERO_FUTURITY = seconds(0);
33 
operator ==(const TimerInfo & other) const34 bool TimerInfo::operator==(const TimerInfo &other) const
35 {
36     return this->id == other.id;
37 }
38 
Matches(const std::string & packageName) const39 bool TimerInfo::Matches(const std::string &packageName) const
40 {
41     return false;
42 }
43 
TimerInfo(std::string _name,uint64_t _id,int _type,std::chrono::milliseconds _when,std::chrono::steady_clock::time_point _whenElapsed,std::chrono::milliseconds _windowLength,std::chrono::steady_clock::time_point _maxWhen,std::chrono::milliseconds _interval,std::function<int32_t (const uint64_t)> _callback,std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent,uint32_t _flags,bool _autoRestore,int _uid,int _pid,const std::string & _bundleName)44 TimerInfo::TimerInfo(std::string _name, uint64_t _id, int _type,
45                      std::chrono::milliseconds _when,
46                      std::chrono::steady_clock::time_point _whenElapsed,
47                      std::chrono::milliseconds _windowLength,
48                      std::chrono::steady_clock::time_point _maxWhen,
49                      std::chrono::milliseconds _interval,
50                      std::function<int32_t (const uint64_t)> _callback,
51                      std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent,
52                      uint32_t _flags,
53                      bool _autoRestore,
54                      int _uid,
55                      int _pid,
56                      const std::string &_bundleName)
57     : name {_name},
58       id {_id},
59       type {_type},
60       origWhen {_when},
61       wakeup {_type == ITimerManager::ELAPSED_REALTIME_WAKEUP || _type == ITimerManager::RTC_WAKEUP},
62       autoRestore {_autoRestore},
63       callback {std::move(_callback)},
64       wantAgent {_wantAgent},
65       flags {_flags},
66       uid {_uid},
67       pid {_pid},
68       when {_when},
69       windowLength {_windowLength},
70       whenElapsed {_whenElapsed},
71       maxWhenElapsed {_maxWhen},
72       repeatInterval {_interval},
73       bundleName {_bundleName}
74 {
75     originWhenElapsed = _whenElapsed;
76     originMaxWhenElapsed = _maxWhen;
77     state = TimerState::INIT;
78 }
79 
CreateTimerInfo(std::string _name,uint64_t _id,int _type,uint64_t _triggerAtTime,int64_t _windowLength,uint64_t _interval,uint32_t _flag,bool _autoRestore,std::function<int32_t (const uint64_t)> _callback,std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent,int _uid,int _pid,const std::string & _bundleName)80 std::shared_ptr<TimerInfo> TimerInfo::CreateTimerInfo(std::string _name, uint64_t _id, int _type,
81     uint64_t _triggerAtTime,
82     int64_t _windowLength,
83     uint64_t _interval,
84     uint32_t _flag,
85     bool _autoRestore,
86     std::function<int32_t (const uint64_t)> _callback,
87     std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent,
88     int _uid,
89     int _pid,
90     const std::string &_bundleName)
91 {
92     auto windowLengthDuration = milliseconds(_windowLength);
93     if (windowLengthDuration > INTERVAL_HALF_DAY) {
94         windowLengthDuration = INTERVAL_HOUR;
95     }
96     auto intervalDuration = milliseconds(_interval > MAX_MILLISECOND ? MAX_MILLISECOND : _interval);
97     if (intervalDuration > milliseconds::zero() && intervalDuration < MIN_INTERVAL_ONE_SECONDS) {
98         intervalDuration = MIN_INTERVAL_ONE_SECONDS;
99     } else if (intervalDuration > MAX_INTERVAL) {
100         intervalDuration = MAX_INTERVAL;
101     }
102 
103     auto nowElapsed = TimeUtils::GetBootTimeNs();
104     auto triggerTime = milliseconds(_triggerAtTime > MAX_MILLISECOND ? MAX_MILLISECOND : _triggerAtTime);
105     auto nominalTrigger = ConvertToElapsed(triggerTime, _type);
106     auto minTrigger = nowElapsed + ZERO_FUTURITY;
107     auto triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
108 
109     steady_clock::time_point maxElapsed;
110     if (windowLengthDuration == milliseconds::zero()) {
111         maxElapsed = triggerElapsed;
112     } else if (windowLengthDuration < milliseconds::zero()) {
113         maxElapsed = MaxTriggerTime(nominalTrigger, triggerElapsed, intervalDuration);
114         windowLengthDuration = duration_cast<milliseconds>(maxElapsed - triggerElapsed);
115     } else {
116         maxElapsed = triggerElapsed + windowLengthDuration;
117     }
118     return std::make_shared<TimerInfo>(_name, _id, _type, triggerTime, triggerElapsed, windowLengthDuration, maxElapsed,
119         intervalDuration, std::move(_callback), _wantAgent, _flag, _autoRestore, _uid,
120         _pid, _bundleName);
121 }
122 
CalculateOriWhenElapsed()123 void TimerInfo::CalculateOriWhenElapsed()
124 {
125     auto nowElapsed = TimeUtils::GetBootTimeNs();
126     auto elapsed = ConvertToElapsed(origWhen, type);
127     steady_clock::time_point maxElapsed;
128     if (windowLength == milliseconds::zero()) {
129         maxElapsed = elapsed;
130     } else {
131         maxElapsed = (windowLength > milliseconds::zero()) ?
132                      (elapsed + windowLength) :
133                      MaxTriggerTime(nowElapsed, elapsed, repeatInterval);
134     }
135     originWhenElapsed = elapsed;
136     originMaxWhenElapsed = maxElapsed;
137 }
138 
CalculateWhenElapsed(std::chrono::steady_clock::time_point nowElapsed)139 void TimerInfo::CalculateWhenElapsed(std::chrono::steady_clock::time_point nowElapsed)
140 {
141     auto Elapsed = ConvertToElapsed(when, type);
142     steady_clock::time_point maxElapsed;
143     if (windowLength == milliseconds::zero()) {
144         maxElapsed = Elapsed;
145     } else {
146         maxElapsed = (windowLength > milliseconds::zero()) ?
147                      (Elapsed + windowLength) :
148                      MaxTriggerTime(nowElapsed, Elapsed, repeatInterval);
149     }
150     whenElapsed = Elapsed;
151     maxWhenElapsed = maxElapsed;
152 }
153 
154 /* Please make sure that the first param is current boottime */
UpdateWhenElapsedFromNow(std::chrono::steady_clock::time_point now,std::chrono::nanoseconds offset)155 bool TimerInfo::UpdateWhenElapsedFromNow(std::chrono::steady_clock::time_point now, std::chrono::nanoseconds offset)
156 {
157     TIME_HILOGD(TIME_MODULE_SERVICE, "Update whenElapsed, id=%{public}" PRId64 "", id);
158     auto oldWhenElapsed = whenElapsed;
159     whenElapsed = now + offset;
160     auto oldMaxWhenElapsed = maxWhenElapsed;
161     maxWhenElapsed = whenElapsed + windowLength;
162     std::chrono::milliseconds currentTime;
163     if (type == ITimerManager::RTC || type == ITimerManager::RTC_WAKEUP) {
164         currentTime =
165             std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
166     } else {
167         currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
168     }
169     auto offsetMill = std::chrono::duration_cast<std::chrono::milliseconds>(offset);
170     when = currentTime + offsetMill;
171     return (oldWhenElapsed != whenElapsed) || (oldMaxWhenElapsed != maxWhenElapsed);
172 }
173 
ProxyTimer(const std::chrono::steady_clock::time_point & now,std::chrono::nanoseconds deltaTime)174 bool TimerInfo::ProxyTimer(const std::chrono::steady_clock::time_point &now, std::chrono::nanoseconds deltaTime)
175 {
176     auto res = UpdateWhenElapsedFromNow(now, deltaTime);
177     //Change timer state
178     state = TimerState::PROXY;
179     return res;
180 }
181 
RestoreProxyTimer()182 bool TimerInfo::RestoreProxyTimer()
183 {
184     //Change timer state
185     switch (state) {
186         case INIT:
187             TIME_HILOGE(TIME_MODULE_SERVICE, "Restore timer in init state, id: %{public}" PRIu64 "", id);
188             break;
189         case ADJUST:
190             TIME_HILOGE(TIME_MODULE_SERVICE, "Restore timer in adjust state, id: %{public}" PRIu64 "", id);
191             state = INIT;
192             break;
193         case PROXY:
194             state = INIT;
195             break;
196         default:
197             TIME_HILOGE(TIME_MODULE_SERVICE, "Error state, id: %{public}" PRIu64 ", state: %{public}d", id, state);
198     }
199     return RestoreTimer();
200 }
201 
AdjustTimer(const std::chrono::steady_clock::time_point & now,const uint32_t interval,const uint32_t delta)202 bool TimerInfo::AdjustTimer(const std::chrono::steady_clock::time_point &now,
203                             const uint32_t interval, const uint32_t delta)
204 {
205     auto oldWhenElapsed = whenElapsed;
206     auto oldMaxWhenElapsed = maxWhenElapsed;
207     std::chrono::duration<int, std::ratio<1, HALF_SECEND>> halfIntervalSec(interval);
208     std::chrono::duration<int, std::ratio<1, 1>> intervalSec(interval);
209     std::chrono::duration<int, std::ratio<1, 1>> deltaSec(delta);
210     auto oldTimeSec = std::chrono::duration_cast<std::chrono::seconds>(whenElapsed.time_since_epoch());
211     auto timeSec = ((oldTimeSec + halfIntervalSec) / intervalSec) * intervalSec + deltaSec;
212     whenElapsed = std::chrono::steady_clock::time_point(timeSec);
213     if (windowLength == std::chrono::milliseconds::zero()) {
214         maxWhenElapsed = whenElapsed;
215     } else {
216         auto oldMaxTimeSec = std::chrono::duration_cast<std::chrono::seconds>(maxWhenElapsed.time_since_epoch());
217         auto maxTimeSec = ((oldMaxTimeSec + halfIntervalSec) / intervalSec) * intervalSec + deltaSec;
218         maxWhenElapsed = std::chrono::steady_clock::time_point(maxTimeSec);
219     }
220     if (whenElapsed < now) {
221         whenElapsed += std::chrono::duration_cast<std::chrono::milliseconds>(intervalSec);
222     }
223     if (maxWhenElapsed < now) {
224         maxWhenElapsed += std::chrono::duration_cast<std::chrono::milliseconds>(intervalSec);
225     }
226     auto elapsedDelta = std::chrono::duration_cast<std::chrono::milliseconds>(
227         whenElapsed.time_since_epoch() - oldWhenElapsed.time_since_epoch());
228     when = when + elapsedDelta;
229     return (oldWhenElapsed != whenElapsed) || (oldMaxWhenElapsed != maxWhenElapsed);
230 }
231 
RestoreAdjustTimer()232 bool TimerInfo::RestoreAdjustTimer()
233 {
234     //Change timer state
235     switch (state) {
236         case INIT:
237             TIME_HILOGE(TIME_MODULE_SERVICE, "Restore timer in init state, id: %{public}" PRIu64"", id);
238             break;
239         case ADJUST:
240             state = INIT;
241             break;
242         case PROXY:
243             return true;
244         default:
245             TIME_HILOGE(TIME_MODULE_SERVICE, "Error state, id: %{public}" PRIu64 ", state: %{public}d", id, state);
246     }
247     return RestoreTimer();
248 }
249 
RestoreTimer()250 bool TimerInfo::RestoreTimer()
251 {
252     CalculateOriWhenElapsed();
253     auto oldWhenElapsed = whenElapsed;
254     auto oldMaxWhenElapsed = maxWhenElapsed;
255     auto oldWhen = when;
256     whenElapsed = originWhenElapsed;
257     maxWhenElapsed = originMaxWhenElapsed;
258     when = origWhen;
259     return (oldWhenElapsed != whenElapsed) || (oldMaxWhenElapsed != maxWhenElapsed) || (oldWhen != when);
260 }
261 
ConvertToElapsed(std::chrono::milliseconds when,int type)262 std::chrono::steady_clock::time_point TimerInfo::ConvertToElapsed(std::chrono::milliseconds when, int type)
263 {
264     if (type == ITimerManager::RTC || type == ITimerManager::RTC_WAKEUP) {
265         auto systemTimeNow = system_clock::now().time_since_epoch();
266         auto bootTimePoint = TimeUtils::GetBootTimeNs();
267         auto offset = when - systemTimeNow;
268         TIME_HILOGD(TIME_MODULE_SERVICE, "systemTimeNow : %{public}lld offset : %{public}lld",
269                     systemTimeNow.count(), offset.count());
270         return bootTimePoint + offset;
271     }
272     std::chrono::steady_clock::time_point elapsed (when);
273     return elapsed;
274 }
275 
MaxTriggerTime(steady_clock::time_point now,steady_clock::time_point triggerAtTime,milliseconds interval)276 steady_clock::time_point TimerInfo::MaxTriggerTime(steady_clock::time_point now,
277                                                    steady_clock::time_point triggerAtTime,
278                                                    milliseconds interval)
279 {
280     milliseconds futurity = (interval == milliseconds::zero()) ?
281                             (duration_cast<milliseconds>(triggerAtTime - now)) : interval;
282     if (futurity < MIN_FUZZABLE_INTERVAL) {
283         futurity = milliseconds::zero();
284     }
285     return triggerAtTime + milliseconds(static_cast<long>(BATCH_WINDOW_COE * futurity.count()));
286 }
287 } // MiscServices
288 } // OHOS