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