1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "TimerProvider.h"
18
19 #include <chrono>
20 #include <string>
21
22 #include <android-base/logging.h>
23 #include <input/PrintTools.h>
24
25 namespace android {
26
27 namespace {
28
stimeToNsecs(stime_t time)29 nsecs_t stimeToNsecs(stime_t time) {
30 return std::chrono::duration_cast<std::chrono::nanoseconds>(
31 std::chrono::duration<stime_t>(time))
32 .count();
33 }
34
nsecsToStime(nsecs_t time)35 stime_t nsecsToStime(nsecs_t time) {
36 return std::chrono::duration_cast<std::chrono::duration<stime_t>>(
37 std::chrono::nanoseconds(time))
38 .count();
39 }
40
createTimer(void * data)41 GesturesTimer* createTimer(void* data) {
42 return static_cast<TimerProvider*>(data)->createTimer();
43 }
44
setDeadline(void * data,GesturesTimer * timer,stime_t delay,GesturesTimerCallback callback,void * callbackData)45 void setDeadline(void* data, GesturesTimer* timer, stime_t delay, GesturesTimerCallback callback,
46 void* callbackData) {
47 static_cast<TimerProvider*>(data)->setDeadline(timer, stimeToNsecs(delay), callback,
48 callbackData);
49 };
50
cancelTimer(void * data,GesturesTimer * timer)51 void cancelTimer(void* data, GesturesTimer* timer) {
52 static_cast<TimerProvider*>(data)->cancelTimer(timer);
53 }
54
freeTimer(void * data,GesturesTimer * timer)55 void freeTimer(void* data, GesturesTimer* timer) {
56 static_cast<TimerProvider*>(data)->freeTimer(timer);
57 }
58
59 } // namespace
60
61 const GesturesTimerProvider kGestureTimerProvider = {
62 .create_fn = createTimer,
63 .set_fn = setDeadline,
64 .cancel_fn = cancelTimer,
65 .free_fn = freeTimer,
66 };
67
TimerProvider(InputReaderContext & context)68 TimerProvider::TimerProvider(InputReaderContext& context) : mReaderContext(context) {}
69
dump()70 std::string TimerProvider::dump() {
71 std::string dump;
72 auto timerPtrToString = [](const std::unique_ptr<GesturesTimer>& timer) {
73 return std::to_string(timer->id);
74 };
75 dump += "Timer IDs: " + dumpVector<std::unique_ptr<GesturesTimer>>(mTimers, timerPtrToString) +
76 "\n";
77 dump += "Deadlines and corresponding timer IDs:\n";
78 dump += addLinePrefix(dumpMap(mDeadlines, constToString,
79 [](const Deadline& deadline) {
80 return std::to_string(deadline.timerId);
81 }),
82 " ") +
83 "\n";
84 return dump;
85 }
86
triggerCallbacks(nsecs_t when)87 void TimerProvider::triggerCallbacks(nsecs_t when) {
88 while (!mDeadlines.empty() && when >= mDeadlines.begin()->first) {
89 const auto& deadlinePair = mDeadlines.begin();
90 deadlinePair->second.callback(when);
91 mDeadlines.erase(deadlinePair);
92 }
93 requestTimeout();
94 }
95
createTimer()96 GesturesTimer* TimerProvider::createTimer() {
97 mTimers.push_back(std::make_unique<GesturesTimer>());
98 mTimers.back()->id = mNextTimerId;
99 mNextTimerId++;
100 return mTimers.back().get();
101 }
102
setDeadline(GesturesTimer * timer,nsecs_t delay,GesturesTimerCallback callback,void * callbackData)103 void TimerProvider::setDeadline(GesturesTimer* timer, nsecs_t delay, GesturesTimerCallback callback,
104 void* callbackData) {
105 setDeadlineWithoutRequestingTimeout(timer, delay, callback, callbackData);
106 requestTimeout();
107 }
108
setDeadlineWithoutRequestingTimeout(GesturesTimer * timer,nsecs_t delay,GesturesTimerCallback callback,void * callbackData)109 void TimerProvider::setDeadlineWithoutRequestingTimeout(GesturesTimer* timer, nsecs_t delay,
110 GesturesTimerCallback callback,
111 void* callbackData) {
112 const nsecs_t now = getCurrentTime();
113 const nsecs_t time = now + delay;
114 std::function<void(nsecs_t)> wrappedCallback = [=, this](nsecs_t triggerTime) {
115 stime_t nextDelay = callback(nsecsToStime(triggerTime), callbackData);
116 if (nextDelay >= 0.0) {
117 // When rescheduling a deadline, we know that we're running inside a call to
118 // triggerCallbacks, at the end of which requestTimeout will be called. This means that
119 // we don't want to call the public setDeadline, as that will request a timeout before
120 // triggerCallbacks has removed this current deadline, resulting in a request for a
121 // timeout that has already passed.
122 setDeadlineWithoutRequestingTimeout(timer, stimeToNsecs(nextDelay), callback,
123 callbackData);
124 }
125 };
126 mDeadlines.insert({time, Deadline(wrappedCallback, timer->id)});
127 }
128
cancelTimer(GesturesTimer * timer)129 void TimerProvider::cancelTimer(GesturesTimer* timer) {
130 int id = timer->id;
131 std::erase_if(mDeadlines, [id](const auto& item) { return item.second.timerId == id; });
132 requestTimeout();
133 }
134
freeTimer(GesturesTimer * timer)135 void TimerProvider::freeTimer(GesturesTimer* timer) {
136 cancelTimer(timer);
137 std::erase_if(mTimers, [timer](std::unique_ptr<GesturesTimer>& t) { return t.get() == timer; });
138 }
139
requestTimeout()140 void TimerProvider::requestTimeout() {
141 if (!mDeadlines.empty()) {
142 // Because a std::multimap is sorted by key, we simply use the time for the first entry.
143 mReaderContext.requestTimeoutAtTime(mDeadlines.begin()->first);
144 }
145 }
146
getCurrentTime()147 nsecs_t TimerProvider::getCurrentTime() {
148 return systemTime(SYSTEM_TIME_MONOTONIC);
149 }
150
151 } // namespace android