• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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