1 /*
2  * Copyright (C) 2012 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 #define LOG_TAG "AudioWatchdog"
18 //#define LOG_NDEBUG 0
19 
20 #include "Configuration.h"
21 #include <utils/Log.h>
22 #include "AudioWatchdog.h"
23 
24 #ifdef AUDIO_WATCHDOG
25 
26 namespace android {
27 
dump(int fd)28 void AudioWatchdogDump::dump(int fd)
29 {
30     char buf[32];
31     if (mMostRecent != 0) {
32         // includes NUL terminator
33         ctime_r(&mMostRecent, buf);
34     } else {
35         strcpy(buf, "N/A\n");
36     }
37     dprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
38             mUnderruns, mLogs, buf);
39 }
40 
threadLoop()41 bool AudioWatchdog::threadLoop() NO_THREAD_SAFETY_ANALYSIS // unique_lock
42 {
43     {
44         std::unique_lock _l(mLock);
45         if (mPaused) {
46             mCond.wait(_l);
47             // ignore previous timestamp after resume()
48             mOldTsValid = false;
49             // force an immediate log on first underrun after resume()
50             mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
51             mLogTs.tv_nsec = 0;
52             // caller will check for exitPending()
53             return true;
54         }
55     }
56     struct timespec newTs;
57     int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
58     if (rc != 0) {
59         pause();
60         return false;
61     }
62     if (!mOldTsValid) {
63         mOldTs = newTs;
64         mOldTsValid = true;
65         return true;
66     }
67     time_t sec = newTs.tv_sec - mOldTs.tv_sec;
68     auto nsec = newTs.tv_nsec - mOldTs.tv_nsec;
69     if (nsec < 0) {
70         --sec;
71         nsec += 1000000000;
72     }
73     mOldTs = newTs;
74     // cycleNs is same as sec*1e9 + nsec, but limited to about 4 seconds
75     uint32_t cycleNs = nsec;
76     if (sec > 0) {
77         if (sec < 4) {
78             cycleNs += sec * 1000000000;
79         } else {
80             cycleNs = 4000000000u;
81         }
82     }
83     mLogTs.tv_sec += sec;
84     mLogTs.tv_nsec += nsec;
85     if (mLogTs.tv_nsec >= 1000000000) {
86         mLogTs.tv_sec++;
87         mLogTs.tv_nsec -= 1000000000;
88     }
89     if (cycleNs > mMaxCycleNs) {
90         mDump->mUnderruns = ++mUnderruns;
91         if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) {
92             mDump->mLogs = ++mLogs;
93             mDump->mMostRecent = time(nullptr /* tloc */);
94             ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u",
95                 mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs);
96             mLogTs.tv_sec = 0;
97             mLogTs.tv_nsec = 0;
98         }
99     }
100     struct timespec req;
101     req.tv_sec = 0;
102     req.tv_nsec = mPeriodNs;
103     rc = nanosleep(&req, nullptr /* remaining */);
104     if (!((rc == 0) || (rc == -1 && errno == EINTR))) {
105         pause();
106         return false;
107     }
108     return true;
109 }
110 
requestExit()111 void AudioWatchdog::requestExit()
112 {
113     // must be in this order to avoid a race condition
114     Thread::requestExit();
115     resume();
116 }
117 
pause()118 void AudioWatchdog::pause()
119 {
120     const std::lock_guard _l(mLock);
121     mPaused = true;
122 }
123 
resume()124 void AudioWatchdog::resume()
125 {
126     const std::lock_guard _l(mLock);
127     if (mPaused) {
128         mPaused = false;
129         mCond.notify_one();
130     }
131 }
132 
setDump(AudioWatchdogDump * dump)133 void AudioWatchdog::setDump(AudioWatchdogDump *dump)
134 {
135     const std::lock_guard _l(mLock);
136     mDump = dump != nullptr ? dump : &mDummyDump;
137 }
138 
139 }   // namespace android
140 
141 #endif // AUDIO_WATCHDOG
142