1c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten/* 2c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * Copyright (C) 2012 The Android Open Source Project 3c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * 4c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * you may not use this file except in compliance with the License. 6c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * You may obtain a copy of the License at 7c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * 8c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * 10c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * Unless required by applicable law or agreed to in writing, software 11c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * See the License for the specific language governing permissions and 14c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten * limitations under the License. 15c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten */ 16c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 17c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#define LOG_TAG "AudioWatchdog" 18c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten//#define LOG_NDEBUG 0 19c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 20153b9fe667e6e78e0218ff0159353097428c7657Glenn Kasten#include "Configuration.h" 21c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#include <utils/Log.h> 22c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#include "AudioWatchdog.h" 23c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 24153b9fe667e6e78e0218ff0159353097428c7657Glenn Kasten#ifdef AUDIO_WATCHDOG 25153b9fe667e6e78e0218ff0159353097428c7657Glenn Kasten 26c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastennamespace android { 27c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 28c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenvoid AudioWatchdogDump::dump(int fd) 29c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 30c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten char buf[32]; 31c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (mMostRecent != 0) { 32c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // includes NUL terminator 33c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten ctime_r(&mMostRecent, buf); 34c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } else { 35c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten strcpy(buf, "N/A\n"); 36c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 378b5f642eb2364ea7fe46a5b3af51b48b58f12183Elliott Hughes dprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s", 38c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mUnderruns, mLogs, buf); 39c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 40c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 41c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenbool AudioWatchdog::threadLoop() 42c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 43c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten { 44c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AutoMutex _l(mMyLock); 45c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (mPaused) { 46c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mMyCond.wait(mMyLock); 47c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // ignore previous timestamp after resume() 48c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mOldTsValid = false; 49c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // force an immediate log on first underrun after resume() 50c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC; 51c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_nsec = 0; 52c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // caller will check for exitPending() 53c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten return true; 54c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 55c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 56c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten struct timespec newTs; 57c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 58c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (rc != 0) { 59c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten pause(); 60c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten return false; 61c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 62c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (!mOldTsValid) { 63c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mOldTs = newTs; 64c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mOldTsValid = true; 65c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten return true; 66c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 67c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten time_t sec = newTs.tv_sec - mOldTs.tv_sec; 68c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten long nsec = newTs.tv_nsec - mOldTs.tv_nsec; 69c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (nsec < 0) { 70c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten --sec; 71c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten nsec += 1000000000; 72c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 73c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mOldTs = newTs; 74c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // cycleNs is same as sec*1e9 + nsec, but limited to about 4 seconds 75c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t cycleNs = nsec; 76c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (sec > 0) { 77c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (sec < 4) { 78c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten cycleNs += sec * 1000000000; 79c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } else { 80c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten cycleNs = 4000000000u; 81c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 82c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 83c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_sec += sec; 84c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if ((mLogTs.tv_nsec += nsec) >= 1000000000) { 85c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_sec++; 86c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_nsec -= 1000000000; 87c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 88c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (cycleNs > mMaxCycleNs) { 89c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mDump->mUnderruns = ++mUnderruns; 90c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) { 91c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mDump->mLogs = ++mLogs; 92c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mDump->mMostRecent = time(NULL); 93c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u", 94c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs); 95c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_sec = 0; 96c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_nsec = 0; 97c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 98c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 99c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten struct timespec req; 100c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten req.tv_sec = 0; 101c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten req.tv_nsec = mPeriodNs; 102c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten rc = nanosleep(&req, NULL); 103c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (!((rc == 0) || (rc == -1 && errno == EINTR))) { 104c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten pause(); 105c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten return false; 106c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 107c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten return true; 108c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 109c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 110c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenvoid AudioWatchdog::requestExit() 111c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 112c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // must be in this order to avoid a race condition 113c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten Thread::requestExit(); 114c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten resume(); 115c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 116c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 117c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenvoid AudioWatchdog::pause() 118c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 119c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AutoMutex _l(mMyLock); 120c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mPaused = true; 121c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 122c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 123c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenvoid AudioWatchdog::resume() 124c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 125c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AutoMutex _l(mMyLock); 126c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten if (mPaused) { 127c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mPaused = false; 128c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mMyCond.signal(); 129c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 130c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 131c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 132c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenvoid AudioWatchdog::setDump(AudioWatchdogDump *dump) 133c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten{ 134c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mDump = dump != NULL ? dump : &mDummyDump; 135c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} 136c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 137c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} // namespace android 138153b9fe667e6e78e0218ff0159353097428c7657Glenn Kasten 139153b9fe667e6e78e0218ff0159353097428c7657Glenn Kasten#endif // AUDIO_WATCHDOG 140