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