1 /*
2  * Copyright (C) 2018 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 
18 #include <media/TimeCheck.h>
19 
20 namespace android {
21 
22 /* static */
getTimeCheckThread()23 sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
24 {
25     static sp<TimeCheck::TimeCheckThread> sTimeCheckThread = new TimeCheck::TimeCheckThread();
26     return sTimeCheckThread;
27 }
28 
TimeCheck(const char * tag,uint32_t timeoutMs)29 TimeCheck::TimeCheck(const char *tag, uint32_t timeoutMs)
30     : mEndTimeNs(getTimeCheckThread()->startMonitoring(tag, timeoutMs))
31 {
32 }
33 
~TimeCheck()34 TimeCheck::~TimeCheck() {
35     getTimeCheckThread()->stopMonitoring(mEndTimeNs);
36 }
37 
~TimeCheckThread()38 TimeCheck::TimeCheckThread::~TimeCheckThread()
39 {
40     AutoMutex _l(mMutex);
41     requestExit();
42     mMonitorRequests.clear();
43     mCond.signal();
44 }
45 
startMonitoring(const char * tag,uint32_t timeoutMs)46 nsecs_t TimeCheck::TimeCheckThread::startMonitoring(const char *tag, uint32_t timeoutMs) {
47     Mutex::Autolock _l(mMutex);
48     nsecs_t endTimeNs = systemTime() + milliseconds(timeoutMs);
49     for (; mMonitorRequests.indexOfKey(endTimeNs) >= 0; ++endTimeNs);
50     mMonitorRequests.add(endTimeNs, tag);
51     mCond.signal();
52     return endTimeNs;
53 }
54 
stopMonitoring(nsecs_t endTimeNs)55 void TimeCheck::TimeCheckThread::stopMonitoring(nsecs_t endTimeNs) {
56     Mutex::Autolock _l(mMutex);
57     mMonitorRequests.removeItem(endTimeNs);
58     mCond.signal();
59 }
60 
threadLoop()61 bool TimeCheck::TimeCheckThread::threadLoop()
62 {
63     status_t status = TIMED_OUT;
64     const char *tag;
65     {
66         AutoMutex _l(mMutex);
67 
68         if (exitPending()) {
69             return false;
70         }
71 
72         nsecs_t endTimeNs = INT64_MAX;
73         // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
74         if (mMonitorRequests.size() != 0) {
75             endTimeNs = mMonitorRequests.keyAt(0);
76             tag = mMonitorRequests.valueAt(0);
77         }
78 
79         const nsecs_t waitTimeNs = endTimeNs - systemTime();
80         if (waitTimeNs > 0) {
81             status = mCond.waitRelative(mMutex, waitTimeNs);
82         }
83     }
84     LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
85     return true;
86 }
87 
88 }; // namespace android
89