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