1 /**
2  * Copyright (C) 2022 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 <ImsMediaTimer.h>
18 #include <ImsMediaTrace.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24 #include <chrono>
25 #include <thread>
26 #include <utils/Atomic.h>
27 #include <limits.h>
28 #include <mutex>
29 #include <list>
30 #include <algorithm>
31 
32 struct TimerInstance
33 {
34     fn_TimerCb mTimerCb;
35     uint32_t mDuration;
36     bool mRepeat;
37     void* mUserData;
38     bool mTerminateThread;
39     uint32_t mStartTimeMillisecond;
40     std::mutex mMutex;
41 };
42 
43 static std::mutex gMutexList;
44 static std::list<TimerInstance*> gTimerList;
45 static std::uint64_t gStartTime = 0;
46 
AddTimerToList(TimerInstance * timer)47 static void AddTimerToList(TimerInstance* timer)
48 {
49     std::lock_guard<std::mutex> guard(gMutexList);
50     gTimerList.push_back(timer);
51 }
52 
DeleteTimerFromList(TimerInstance * timer)53 static void DeleteTimerFromList(TimerInstance* timer)
54 {
55     std::lock_guard<std::mutex> guard(gMutexList);
56     gTimerList.remove(timer);
57 }
58 
IsValidTimer(const TimerInstance * timer)59 static bool IsValidTimer(const TimerInstance* timer)
60 {
61     std::lock_guard<std::mutex> guard(gMutexList);
62 
63     if (gTimerList.empty())
64     {
65         return false;
66     }
67 
68     auto result = std::find(gTimerList.begin(), gTimerList.end(), timer);
69     return (result != gTimerList.end());
70 }
71 
ImsMediaTimer_run(void * arg)72 static void* ImsMediaTimer_run(void* arg)
73 {
74     TimerInstance* timer = reinterpret_cast<TimerInstance*>(arg);
75 
76     if (timer == nullptr)
77     {
78         return nullptr;
79     }
80 
81     uint32_t sleepTime = timer->mDuration;
82 
83     if (timer->mDuration > 10 && timer->mDuration < 100)
84     {
85         sleepTime = 10;
86     }
87     else if (timer->mDuration >= 100 && timer->mDuration < 1000)
88     {
89         sleepTime = timer->mDuration / 10;
90     }
91     else if (timer->mDuration >= 1000)
92     {
93         sleepTime = 100;
94     }
95 
96     for (;;)
97     {
98         if (timer->mTerminateThread)
99         {
100             break;
101         }
102 
103         std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
104 
105         if (timer->mTerminateThread)
106         {
107             break;
108         }
109 
110         uint32_t currTimeMillisecond = ImsMediaTimer::GetTimeInMilliSeconds();
111         uint32_t nTimeDiff = currTimeMillisecond - timer->mStartTimeMillisecond;
112 
113         if (nTimeDiff >= timer->mDuration)
114         {
115             if (timer->mRepeat)
116             {
117                 timer->mStartTimeMillisecond = currTimeMillisecond;
118             }
119 
120             {  // Critical section
121                 std::lock_guard<std::mutex> guard(timer->mMutex);
122                 if (timer->mTerminateThread)
123                 {
124                     break;
125                 }
126 
127                 if (timer->mTimerCb)
128                 {
129                     timer->mTimerCb(timer, timer->mUserData);
130                 }
131             }
132 
133             if (!timer->mRepeat)
134             {
135                 break;
136             }
137         }
138     }
139 
140     DeleteTimerFromList(timer);
141 
142     if (timer != nullptr)
143     {
144         delete timer;
145         timer = nullptr;
146     }
147 
148     return nullptr;
149 }
150 
TimerStart(uint32_t duration,bool repeat,fn_TimerCb timerCallback,void * userData)151 hTimerHandler ImsMediaTimer::TimerStart(
152         uint32_t duration, bool repeat, fn_TimerCb timerCallback, void* userData)
153 {
154     TimerInstance* timer = new TimerInstance;
155 
156     if (timer == nullptr)
157     {
158         return nullptr;
159     }
160 
161     timer->mTimerCb = timerCallback;
162     timer->mDuration = duration;
163     timer->mRepeat = repeat;
164     timer->mUserData = userData;
165     timer->mTerminateThread = false;
166 
167     IMLOGD3("[TimerStart] duration[%u], repeat[%d], userData[%x]", timer->mDuration, repeat,
168             timer->mUserData);
169 
170     timer->mStartTimeMillisecond = ImsMediaTimer::GetTimeInMilliSeconds();
171     AddTimerToList(timer);
172 
173     std::thread t1(&ImsMediaTimer_run, timer);
174     t1.detach();
175     return (hTimerHandler)timer;
176 }
177 
TimerStop(hTimerHandler hTimer,void ** puserData)178 bool ImsMediaTimer::TimerStop(hTimerHandler hTimer, void** puserData)
179 {
180     TimerInstance* timer = reinterpret_cast<TimerInstance*>(hTimer);
181     IMLOGD1("[TimerStop] timer[%x]", timer);
182 
183     if (timer == nullptr)
184     {
185         return false;
186     }
187 
188     if (IsValidTimer(timer) == false)
189     {
190         return false;
191     }
192 
193     {
194         std::lock_guard<std::mutex> guard(timer->mMutex);
195         IMLOGD1("[TimerStop] mutex taken timer[%x]", timer);
196 
197         timer->mTerminateThread = true;
198 
199         if (puserData)
200         {
201             *puserData = timer->mUserData;
202         }
203     }
204 
205     return true;
206 }
207 
SetStartTimeInMicroSeconds(uint64_t time)208 void ImsMediaTimer::SetStartTimeInMicroSeconds(uint64_t time)
209 {
210     gStartTime = time;
211 }
212 
GetTimeInMicroSeconds(void)213 uint64_t ImsMediaTimer::GetTimeInMicroSeconds(void)
214 {
215     struct timespec time;
216     clock_gettime(CLOCK_MONOTONIC, &time);
217     return gStartTime + (time.tv_sec * 1000000) + (time.tv_nsec / 1000);
218 }
219 
GetTimeInMilliSeconds(void)220 uint32_t ImsMediaTimer::GetTimeInMilliSeconds(void)
221 {
222     return (ImsMediaTimer::GetTimeInMicroSeconds() / 1000 % UINT_MAX);
223 }
224 
GenerateRandom(uint32_t nRange)225 uint32_t ImsMediaTimer::GenerateRandom(uint32_t nRange)
226 {
227     uint32_t rand;
228     struct timespec time;
229     clock_gettime(CLOCK_MONOTONIC, &time);
230     rand = (time.tv_sec * 13) + (time.tv_nsec / 1000000);
231 
232     if (0 == nRange)
233     {
234         return rand * 7;
235     }
236 
237     return (rand * 7) % nRange;
238 }
239 
Atomic_Inc(int32_t * v)240 int32_t ImsMediaTimer::Atomic_Inc(int32_t* v)
241 {
242     return android_atomic_inc(v);
243 }
Atomic_Dec(int32_t * v)244 int32_t ImsMediaTimer::Atomic_Dec(int32_t* v)
245 {
246     return android_atomic_dec(v);
247 }
248 
Sleep(unsigned int t)249 void ImsMediaTimer::Sleep(unsigned int t)
250 {
251     std::this_thread::sleep_for(std::chrono::milliseconds(t));
252 }
253 
USleep(unsigned int t)254 void ImsMediaTimer::USleep(unsigned int t)
255 {
256     std::this_thread::sleep_for(std::chrono::microseconds(t));
257 }