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