Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fd95182 authored by Matthew Bouyack's avatar Matthew Bouyack
Browse files

Track elapsed time for 'waitStreamEnd' timeout

Total elapsed time was not being updated and so 'waitStreamEnd' could
never time out. Allowing timeout to work correctly avoids certain
deadlocks.

Note that the new logic matches that in ClientProxy::obtainBuffer.

Test: CTS : AudioTrackOffloadTest#testMP3AudioTrackOffload
Bug: 207382575
Change-Id: I118fec778aab86ad53bef144d2a231cac08a1f2c
parent 5762c467
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -490,6 +490,8 @@ bool AudioTrackClientProxy::getStreamEndDone() const {
status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
{
    struct timespec total;          // total elapsed time spent waiting
    struct timespec before;
    bool beforeIsValid = false;
    total.tv_sec = 0;
    total.tv_nsec = 0;
    audio_track_cblk_t* cblk = mCblk;
@@ -570,17 +572,38 @@ status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *request
        }
        int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
        if (!(old & CBLK_FUTEX_WAKE)) {
            if (!beforeIsValid) {
                clock_gettime(CLOCK_MONOTONIC, &before);
                beforeIsValid = true;
            }
            errno = 0;
            (void) syscall(__NR_futex, &cblk->mFutex,
                    mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
            switch (errno) {
            status_t error = errno; // clock_gettime can affect errno
            {
                struct timespec after;
                clock_gettime(CLOCK_MONOTONIC, &after);
                total.tv_sec += after.tv_sec - before.tv_sec;
                // Use auto instead of long to avoid the google-runtime-int warning.
                auto deltaNs = after.tv_nsec - before.tv_nsec;
                if (deltaNs < 0) {
                    deltaNs += 1000000000;
                    total.tv_sec--;
                }
                if ((total.tv_nsec += deltaNs) >= 1000000000) {
                    total.tv_nsec -= 1000000000;
                    total.tv_sec++;
                }
                before = after;
            }
            switch (error) {
            case 0:            // normal wakeup by server, or by binderDied()
            case EWOULDBLOCK:  // benign race condition with server
            case EINTR:        // wait was interrupted by signal or other spurious wakeup
            case ETIMEDOUT:    // time-out expired
                break;
            default:
                status = errno;
                status = error;
                ALOGE("%s unexpected error %s", __func__, strerror(status));
                goto end;
            }