• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "RecurrentTimer.h"
18 
19 #include <utils/Log.h>
20 #include <utils/Looper.h>
21 #include <utils/SystemClock.h>
22 
23 #include <inttypes.h>
24 #include <math.h>
25 
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace vehicle {
30 
31 namespace {
32 
33 using ::android::base::ScopedLockAssertion;
34 
35 constexpr int INVALID_ID = -1;
36 
37 }  // namespace
38 
RecurrentTimer()39 RecurrentTimer::RecurrentTimer() {
40     mHandler = sp<RecurrentMessageHandler>::make(this);
41     mLooper = sp<Looper>::make(/*allowNonCallbacks=*/false);
42     mThread = std::thread([this] {
43         Looper::setForThread(mLooper);
44 
45         while (!mStopRequested) {
46             mLooper->pollOnce(/*timeoutMillis=*/-1);
47         }
48     });
49 }
50 
~RecurrentTimer()51 RecurrentTimer::~RecurrentTimer() {
52     mStopRequested = true;
53     mLooper->removeMessages(mHandler);
54     mLooper->wake();
55     if (mThread.joinable()) {
56         mThread.join();
57     }
58 }
59 
getCallbackIdLocked(std::shared_ptr<RecurrentTimer::Callback> callback)60 int RecurrentTimer::getCallbackIdLocked(std::shared_ptr<RecurrentTimer::Callback> callback) {
61     const auto& it = mIdByCallback.find(callback);
62     if (it != mIdByCallback.end()) {
63         return it->second;
64     }
65     return INVALID_ID;
66 }
67 
registerTimerCallback(int64_t intervalInNanos,std::shared_ptr<RecurrentTimer::Callback> callback)68 void RecurrentTimer::registerTimerCallback(int64_t intervalInNanos,
69                                            std::shared_ptr<RecurrentTimer::Callback> callback) {
70     {
71         std::scoped_lock<std::mutex> lockGuard(mLock);
72 
73         int callbackId = getCallbackIdLocked(callback);
74 
75         if (callbackId == INVALID_ID) {
76             callbackId = mCallbackId++;
77             mIdByCallback.insert({callback, callbackId});
78         } else {
79             ALOGI("Replacing an existing timer callback with a new interval, current: %" PRId64
80                   " ns, new: %" PRId64 " ns",
81                   mCallbackInfoById[callbackId]->intervalInNanos, intervalInNanos);
82             mLooper->removeMessages(mHandler, callbackId);
83         }
84 
85         // Aligns the nextTime to multiply of interval.
86         int64_t nextTimeInNanos = ceil(uptimeNanos() / intervalInNanos) * intervalInNanos;
87 
88         std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
89         info->callback = callback;
90         info->intervalInNanos = intervalInNanos;
91         info->nextTimeInNanos = nextTimeInNanos;
92         mCallbackInfoById.insert({callbackId, std::move(info)});
93 
94         mLooper->sendMessageAtTime(nextTimeInNanos, mHandler, Message(callbackId));
95     }
96 }
97 
unregisterTimerCallback(std::shared_ptr<RecurrentTimer::Callback> callback)98 void RecurrentTimer::unregisterTimerCallback(std::shared_ptr<RecurrentTimer::Callback> callback) {
99     {
100         std::scoped_lock<std::mutex> lockGuard(mLock);
101 
102         int callbackId = getCallbackIdLocked(callback);
103 
104         if (callbackId == INVALID_ID) {
105             ALOGE("No event found to unregister");
106             return;
107         }
108 
109         mLooper->removeMessages(mHandler, callbackId);
110         mCallbackInfoById.erase(callbackId);
111         mIdByCallback.erase(callback);
112     }
113 }
114 
handleMessage(const Message & message)115 void RecurrentTimer::handleMessage(const Message& message) {
116     std::shared_ptr<RecurrentTimer::Callback> callback;
117     {
118         std::scoped_lock<std::mutex> lockGuard(mLock);
119 
120         int callbackId = message.what;
121 
122         auto it = mCallbackInfoById.find(callbackId);
123         if (it == mCallbackInfoById.end()) {
124             ALOGW("The event for callback ID: %d is outdated, ignore", callbackId);
125             return;
126         }
127 
128         CallbackInfo* callbackInfo = it->second.get();
129         callback = callbackInfo->callback;
130         int64_t nowNanos = uptimeNanos();
131         // intervalCount is the number of interval we have to advance until we pass now.
132         size_t intervalCount =
133                 (nowNanos - callbackInfo->nextTimeInNanos) / callbackInfo->intervalInNanos + 1;
134         callbackInfo->nextTimeInNanos += intervalCount * callbackInfo->intervalInNanos;
135 
136         mLooper->sendMessageAtTime(callbackInfo->nextTimeInNanos, mHandler, Message(callbackId));
137     }
138 
139     (*callback)();
140 }
141 
handleMessage(const Message & message)142 void RecurrentMessageHandler::handleMessage(const Message& message) {
143     mTimer->handleMessage(message);
144 }
145 
146 }  // namespace vehicle
147 }  // namespace automotive
148 }  // namespace hardware
149 }  // namespace android
150