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()
42 {
43     {
44         AutoMutex _l(mMyLock);
45         if (mPaused) {
46             mMyCond.wait(mMyLock);
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     long 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     if ((mLogTs.tv_nsec += nsec) >= 1000000000) {
85         mLogTs.tv_sec++;
86         mLogTs.tv_nsec -= 1000000000;
87     }
88     if (cycleNs > mMaxCycleNs) {
89         mDump->mUnderruns = ++mUnderruns;
90         if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) {
91             mDump->mLogs = ++mLogs;
92             mDump->mMostRecent = time(NULL);
93             ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u",
94                 mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs);
95             mLogTs.tv_sec = 0;
96             mLogTs.tv_nsec = 0;
97         }
98     }
99     struct timespec req;
100     req.tv_sec = 0;
101     req.tv_nsec = mPeriodNs;
102     rc = nanosleep(&req, NULL);
103     if (!((rc == 0) || (rc == -1 && errno == EINTR))) {
104         pause();
105         return false;
106     }
107     return true;
108 }
109 
requestExit()110 void AudioWatchdog::requestExit()
111 {
112     // must be in this order to avoid a race condition
113     Thread::requestExit();
114     resume();
115 }
116 
pause()117 void AudioWatchdog::pause()
118 {
119     AutoMutex _l(mMyLock);
120     mPaused = true;
121 }
122 
resume()123 void AudioWatchdog::resume()
124 {
125     AutoMutex _l(mMyLock);
126     if (mPaused) {
127         mPaused = false;
128         mMyCond.signal();
129     }
130 }
131 
setDump(AudioWatchdogDump * dump)132 void AudioWatchdog::setDump(AudioWatchdogDump *dump)
133 {
134     mDump = dump != NULL ? dump : &mDummyDump;
135 }
136 
137 }   // namespace android
138 
139 #endif // AUDIO_WATCHDOG
140