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 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 fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s", 38 mUnderruns, mLogs, buf); 39 } 40 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 110 void AudioWatchdog::requestExit() 111 { 112 // must be in this order to avoid a race condition 113 Thread::requestExit(); 114 resume(); 115 } 116 117 void AudioWatchdog::pause() 118 { 119 AutoMutex _l(mMyLock); 120 mPaused = true; 121 } 122 123 void AudioWatchdog::resume() 124 { 125 AutoMutex _l(mMyLock); 126 if (mPaused) { 127 mPaused = false; 128 mMyCond.signal(); 129 } 130 } 131 132 void AudioWatchdog::setDump(AudioWatchdogDump *dump) 133 { 134 mDump = dump != NULL ? dump : &mDummyDump; 135 } 136 137 } // namespace android 138 139 #endif // AUDIO_WATCHDOG 140