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// The watchdog thread runs periodically. It has two functions: 18c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten// (a) verify that adequate CPU time is available, and log 19c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten// as soon as possible when there appears to be a CPU shortage 20c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten// (b) monitor the other threads [not yet implemented] 21c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 22c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#ifndef AUDIO_WATCHDOG_H 23c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#define AUDIO_WATCHDOG_H 24c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 25c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#include <time.h> 26c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#include <utils/Thread.h> 27c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 28c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastennamespace android { 29c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 30c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten// Keeps a cache of AudioWatchdog statistics that can be logged by dumpsys. 31c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten// The usual caveats about atomicity of information apply. 32c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenstruct AudioWatchdogDump { 33c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AudioWatchdogDump() : mUnderruns(0), mLogs(0), mMostRecent(0) { } 34c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten /*virtual*/ ~AudioWatchdogDump() { } 35c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mUnderruns; // total number of underruns 36c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mLogs; // total number of log messages 37c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten time_t mMostRecent; // time of most recent log 38c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten void dump(int fd); // should only be called on a stable copy, not the original 39c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten}; 40c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 41c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenclass AudioWatchdog : public Thread { 42c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 43c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenpublic: 44c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AudioWatchdog(unsigned periodMs = 50) : Thread(false /*canCallJava*/), mPaused(false), 45c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mPeriodNs(periodMs * 1000000), mMaxCycleNs(mPeriodNs * 2), 46c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // mOldTs 47c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // mLogTs initialized below 48c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mOldTsValid(false), mUnderruns(0), mLogs(0), mDump(&mDummyDump) 49c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten { 50c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#define MIN_TIME_BETWEEN_LOGS_SEC 60 51c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // force an immediate log on first underrun 52c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC; 53c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten mLogTs.tv_nsec = 0; 54c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten } 55c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten virtual ~AudioWatchdog() { } 56c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 57c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // Do not call Thread::requestExitAndWait() without first calling requestExit(). 58c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough. 59c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten virtual void requestExit(); 60c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 61c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // FIXME merge API and implementation with AudioTrackThread 62c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten void pause(); // suspend thread from execution at next loop boundary 63c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten void resume(); // allow thread to execute, if not requested to exit 64c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 65c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten // Where to store the dump, or NULL to not update 66c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten void setDump(AudioWatchdogDump* dump); 67c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 68c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kastenprivate: 69c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten virtual bool threadLoop(); 70c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 71c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten Mutex mMyLock; // Thread::mLock is private 72c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten Condition mMyCond; // Thread::mThreadExitedCondition is private 73c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten bool mPaused; // whether thread is currently paused 74c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 75c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mPeriodNs; // nominal period 76c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mMaxCycleNs; // maximum allowed time of one cycle before declaring underrun 77c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten struct timespec mOldTs; // monotonic time when threadLoop last ran 78c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten struct timespec mLogTs; // time since last log 79c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten bool mOldTsValid; // whether mOldTs is valid 80c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mUnderruns; // total number of underruns 81c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten uint32_t mLogs; // total number of logs 82c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AudioWatchdogDump* mDump; // where to store the dump, always non-NULL 83c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten AudioWatchdogDump mDummyDump; // default area for dump in case setDump() is not called 84c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten}; 85c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 86c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten} // namespace android 87c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten 88c15d6657a17d7cef91f800f40d11760e2e7340afGlenn Kasten#endif // AUDIO_WATCHDOG_H 89