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