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

Commit 2f366df6 authored by Andy Hung's avatar Andy Hung
Browse files

AudioFlinger: Associate audio time with client uid

Group active track operations for add and remove together.
PlaybackThread now uses strong pointer for active tracks.

Test: Play Music, Youtube, Batterystats, CTS AudioTrack
Bug: 32361950
Change-Id: Ica96e2b84b9dfa5766571e24de49401a81a30e9d
parent 3ee0f106
Loading
Loading
Loading
Loading
+69 −125
Original line number Diff line number Diff line
@@ -647,8 +647,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
        // mName will be set by concrete (non-virtual) subclass
        mDeathRecipient(new PMDeathRecipient(this)),
        mSystemReady(systemReady),
        mNotifiedBatteryStart(false)
        mSystemReady(systemReady)
{
    memset(&mPatch, 0, sizeof(struct audio_patch));
}
@@ -989,10 +988,10 @@ void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>&
    }
}

void AudioFlinger::ThreadBase::acquireWakeLock(int uid)
void AudioFlinger::ThreadBase::acquireWakeLock()
{
    Mutex::Autolock _l(mLock);
    acquireWakeLock_l(uid);
    acquireWakeLock_l();
}

String16 AudioFlinger::ThreadBase::getWakeLockTag()
@@ -1014,37 +1013,23 @@ String16 AudioFlinger::ThreadBase::getWakeLockTag()
    }
}

void AudioFlinger::ThreadBase::acquireWakeLock_l(int uid)
void AudioFlinger::ThreadBase::acquireWakeLock_l()
{
    getPowerManager_l();
    if (mPowerManager != 0) {
        sp<IBinder> binder = new BBinder();
        status_t status;
        if (uid >= 0) {
            status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
                    binder,
                    getWakeLockTag(),
                    String16("audioserver"),
                    uid,
                    true /* FIXME force oneway contrary to .aidl */);
        } else {
            status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
        // Uses AID_AUDIOSERVER for wakelock.  updateWakeLockUids_l() updates with client uids.
        status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
                    binder,
                    getWakeLockTag(),
                    String16("audioserver"),
                    true /* FIXME force oneway contrary to .aidl */);
        }
        if (status == NO_ERROR) {
            mWakeLockToken = binder;
        }
        ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
    }

    if (!mNotifiedBatteryStart) {
        // TODO: call this function for each track when it becomes active.
        BatteryNotifier::getInstance().noteStartAudio(AID_AUDIOSERVER);
        mNotifiedBatteryStart = true;
    }
    gBoottime.acquire(mWakeLockToken);
    mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
            gBoottime.getBoottimeOffset();
@@ -1067,17 +1052,6 @@ void AudioFlinger::ThreadBase::releaseWakeLock_l()
        }
        mWakeLockToken.clear();
    }

    if (mNotifiedBatteryStart) {
        // TODO: call this function for each track when it becomes inactive.
        BatteryNotifier::getInstance().noteStopAudio(AID_AUDIOSERVER);
        mNotifiedBatteryStart = false;
    }
}

void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) {
    Mutex::Autolock _l(mLock);
    updateWakeLockUids_l(uids);
}

void AudioFlinger::ThreadBase::getPowerManager_l() {
@@ -1096,6 +1070,15 @@ void AudioFlinger::ThreadBase::getPowerManager_l() {

void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
    getPowerManager_l();

#if !LOG_NDEBUG
    std::stringstream s;
    for (int uid : uids) {
        s << uid << " ";
    }
    ALOGD("updateWakeLockUids_l %s uids:%s", mThreadName, s.str().c_str());
#endif

    if (mWakeLockToken == NULL) { // token may be NULL if AudioFlinger::systemReady() not called.
        if (mSystemReady) {
            ALOGE("no wake lock to update, but system ready!");
@@ -1657,6 +1640,41 @@ void AudioFlinger::ThreadBase::systemReady()
    mPendingConfigEvents.clear();
}

template <typename T>
ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::add(const sp<T> &track) {
    ssize_t index = mActiveTracks.indexOf(track);
    if (index >= 0) {
        ALOGW("ActiveTracks<T>::add track %p already there", track.get());
        return index;
    }
    mActiveTracksGeneration++;
    mLatestActiveTrack = track;
    BatteryNotifier::getInstance().noteStartAudio(track->uid());
    return mActiveTracks.add(track);
}

template <typename T>
ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::remove(const sp<T> &track) {
    ssize_t index = mActiveTracks.remove(track);
    if (index < 0) {
        ALOGW("ActiveTracks<T>::remove nonexistent track %p", track.get());
        return index;
    }
    mActiveTracksGeneration++;
    BatteryNotifier::getInstance().noteStopAudio(track->uid());
    // mLatestActiveTrack is not cleared even if is the same as track.
    return index;
}

template <typename T>
void AudioFlinger::ThreadBase::ActiveTracks<T>::clear() {
    for (const sp<T> &track : mActiveTracks) {
        BatteryNotifier::getInstance().noteStopAudio(track->uid());
    }
    mLastActiveTracksGeneration = mActiveTracksGeneration;
    mActiveTracks.clear();
    mLatestActiveTrack.clear();
}

// ----------------------------------------------------------------------------
//      Playback
@@ -1683,7 +1701,6 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
        mSuspended(0), mBytesWritten(0),
        mFramesWritten(0),
        mSuspendedFrames(0),
        mActiveTracksGeneration(0),
        // mStreamTypes[] initialized in constructor body
        mOutput(output),
        mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
@@ -1802,8 +1819,8 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar
        result.append(buffer);
        Track::appendDumpHeader(result);
        for (size_t i = 0; i < numactive; ++i) {
            sp<Track> track = mActiveTracks[i].promote();
            if (track != 0 && mTracks.indexOf(track) < 0) {
            sp<Track> track = mActiveTracks[i];
            if (mTracks.indexOf(track) < 0) {
                track->dump(buffer, SIZE, true);
                result.append(buffer);
            }
@@ -2206,9 +2223,6 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
        track->mResetDone = false;
        track->mPresentationCompleteFrames = 0;
        mActiveTracks.add(track);
        mWakeLockUids.add(track->uid());
        mActiveTracksGeneration++;
        mLatestActiveTrack = track;
        sp<EffectChain> chain = getEffectChain_l(track->sessionId());
        if (chain != 0) {
            ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
@@ -2843,11 +2857,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
        }

        // indicate all active tracks in the chain
        for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
            sp<Track> track = mActiveTracks[i].promote();
            if (track == 0) {
                continue;
            }
        for (const sp<Track> &track : mActiveTracks) {
            if (session == track->sessionId()) {
                ALOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
                chain->incActiveTrackCnt();
@@ -2894,11 +2904,7 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>&
        if (chain == mEffectChains[i]) {
            mEffectChains.removeAt(i);
            // detach all active tracks from the chain
            for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
                sp<Track> track = mActiveTracks[i].promote();
                if (track == 0) {
                    continue;
                }
            for (const sp<Track> &track : mActiveTracks) {
                if (session == track->sessionId()) {
                    ALOGV("removeEffectChain_l(): stopping track on chain %p for session Id: %d",
                            chain.get(), session);
@@ -2975,8 +2981,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
    // FIXME could this be made local to while loop?
    writeFrames = 0;

    int lastGeneration = 0;

    cacheParameters_l();
    mSleepTimeUs = mIdleSleepTimeUs;

@@ -3074,10 +3078,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = mLastWriteTime == -1
                            ? systemTime() : mLastWriteTime;
                }
                const size_t size = mActiveTracks.size();
                for (size_t i = 0; i < size; ++i) {
                    sp<Track> t = mActiveTracks[i].promote();
                    if (t != 0 && !t->isFastTrack()) {

                for (const sp<Track> &t : mActiveTracks) {
                    if (!t->isFastTrack()) {
                        t->updateTrackFrameInfo(
                                t->mAudioTrackServerProxy->framesReleased(),
                                mFramesWritten,
@@ -3098,8 +3101,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                if (!keepWakeLock()) {
                    releaseWakeLock_l();
                    released = true;
                    mWakeLockUids.clear();
                    mActiveTracksGeneration++;
                }
                ALOGV("wait async completion");
                mWaitWorkCV.wait(mLock);
@@ -3133,8 +3134,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                    }

                    releaseWakeLock_l();
                    mWakeLockUids.clear();
                    mActiveTracksGeneration++;
                    // wait until we have something to do...
                    ALOGV("%s going to sleep", myName.string());
                    mWaitWorkCV.wait(mLock);
@@ -3159,12 +3158,7 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            // mMixerStatusIgnoringFastTracks is also updated internally
            mMixerStatus = prepareTracks_l(&tracksToRemove);

            // compare with previously applied list
            if (lastGeneration != mActiveTracksGeneration) {
                // update wakelock
                updateWakeLockUids_l(mWakeLockUids);
                lastGeneration = mActiveTracksGeneration;
            }
            mActiveTracks.updateWakeLockUids(this);

            // prevent any changes in effect chain list and in each effect chain
            // during mixing and effect process as the audio buffers could be deleted
@@ -3382,8 +3376,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
    }

    releaseWakeLock();
    mWakeLockUids.clear();
    mActiveTracksGeneration++;

    ALOGV("Thread %p type %d exiting", this, mType);
    return false;
@@ -3397,8 +3389,6 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tra
        for (size_t i=0 ; i<count ; i++) {
            const sp<Track>& track = tracksToRemove.itemAt(i);
            mActiveTracks.remove(track);
            mWakeLockUids.remove(track->uid());
            mActiveTracksGeneration++;
            ALOGV("removeTracks_l removing track on session %d", track->sessionId());
            sp<EffectChain> chain = getEffectChain_l(track->sessionId());
            if (chain != 0) {
@@ -4017,10 +4007,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
    mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.

    for (size_t i=0 ; i<count ; i++) {
        const sp<Track> t = mActiveTracks[i].promote();
        if (t == 0) {
            continue;
        }
        const sp<Track> t = mActiveTracks[i];

        // this const just means the local variable doesn't change
        Track* const track = t.get();
@@ -4516,11 +4503,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
        size_t i = __builtin_ctz(resetMask);
        ALOG_ASSERT(i < count);
        resetMask &= ~(1 << i);
        sp<Track> t = mActiveTracks[i].promote();
        if (t == 0) {
            continue;
        }
        Track* track = t.get();
        sp<Track> track = mActiveTracks[i];
        ALOG_ASSERT(track->isFastTrack() && track->isStopped());
        track->reset();
    }
@@ -4830,7 +4813,7 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
void AudioFlinger::DirectOutputThread::onAddNewTrack_l()
{
    sp<Track> previousTrack = mPreviousTrack.promote();
    sp<Track> latestTrack = mLatestActiveTrack.promote();
    sp<Track> latestTrack = mActiveTracks.getLatest();

    if (previousTrack != 0 && latestTrack != 0) {
        if (mType == DIRECT) {
@@ -4856,13 +4839,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
    bool doHwResume = false;

    // find out which tracks need to be processed
    for (size_t i = 0; i < count; i++) {
        sp<Track> t = mActiveTracks[i].promote();
        // The track died recently
        if (t == 0) {
            continue;
        }

    for (const sp<Track> &t : mActiveTracks) {
        if (t->isInvalid()) {
            ALOGW("An invalidated track shouldn't be in active list");
            tracksToRemove->add(t);
@@ -4877,7 +4854,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
        // In theory an older track could underrun and restart after the new one starts
        // but as we only care about the transition phase between two tracks on a
        // direct output, it is not a problem to ignore the underrun case.
        sp<Track> l = mLatestActiveTrack.promote();
        sp<Track> l = mActiveTracks.getLatest();
        bool last = l.get() == track;

        if (track->isPausing()) {
@@ -5411,12 +5388,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
    ALOGV("OffloadThread::prepareTracks_l active tracks %zu", count);

    // find out which tracks need to be processed
    for (size_t i = 0; i < count; i++) {
        sp<Track> t = mActiveTracks[i].promote();
        // The track died recently
        if (t == 0) {
            continue;
        }
    for (const sp<Track> &t : mActiveTracks) {
        Track* const track = t.get();
#ifdef VERY_VERY_VERBOSE_LOGGING
        audio_track_cblk_t* cblk = track->cblk();
@@ -5425,7 +5397,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
        // In theory an older track could underrun and restart after the new one starts
        // but as we only care about the transition phase between two tracks on a
        // direct output, it is not a problem to ignore the underrun case.
        sp<Track> l = mLatestActiveTrack.promote();
        sp<Track> l = mActiveTracks.getLatest();
        bool last = l.get() == track;

        if (track->isInvalid()) {
@@ -5884,7 +5856,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
#endif
                                         ) :
    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
    mInput(input), mRsmpInBuffer(NULL),
    // mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
    mRsmpInRear(0)
#ifdef TEE_SINK
@@ -6042,25 +6014,9 @@ bool AudioFlinger::RecordThread::threadLoop()

reacquire_wakelock:
    sp<RecordTrack> activeTrack;
    int activeTracksGen;
    {
        Mutex::Autolock _l(mLock);
        size_t size = mActiveTracks.size();
        activeTracksGen = mActiveTracksGen;
        if (size > 0) {
            // FIXME an arbitrary choice
            activeTrack = mActiveTracks[0];
            acquireWakeLock_l(activeTrack->uid());
            if (size > 1) {
                SortedVector<int> tmp;
                for (size_t i = 0; i < size; i++) {
                    tmp.add(mActiveTracks[i]->uid());
                }
                updateWakeLockUids_l(tmp);
            }
        } else {
            acquireWakeLock_l(-1);
        }
        acquireWakeLock_l();
    }

    // used to request a deferred sleep, to be executed later while mutex is unlocked
@@ -6112,15 +6068,6 @@ reacquire_wakelock:
                goto reacquire_wakelock;
            }

            if (mActiveTracksGen != activeTracksGen) {
                activeTracksGen = mActiveTracksGen;
                SortedVector<int> tmp;
                for (size_t i = 0; i < size; i++) {
                    tmp.add(mActiveTracks[i]->uid());
                }
                updateWakeLockUids_l(tmp);
            }

            bool doBroadcast = false;
            bool allStopped = true;
            for (size_t i = 0; i < size; ) {
@@ -6133,7 +6080,6 @@ reacquire_wakelock:
                    }
                    removeTrack_l(activeTrack);
                    mActiveTracks.remove(activeTrack);
                    mActiveTracksGen++;
                    size--;
                    continue;
                }
@@ -6143,7 +6089,6 @@ reacquire_wakelock:

                case TrackBase::PAUSING:
                    mActiveTracks.remove(activeTrack);
                    mActiveTracksGen++;
                    doBroadcast = true;
                    size--;
                    continue;
@@ -6183,6 +6128,8 @@ reacquire_wakelock:
                }
            }

            mActiveTracks.updateWakeLockUids(this);

            if (allStopped) {
                standbyIfNotAlreadyInStandby();
            }
@@ -6481,7 +6428,6 @@ unlock:
            track->invalidate();
        }
        mActiveTracks.clear();
        mActiveTracksGen++;
        mStartStopCond.broadcast();
    }

@@ -6735,7 +6681,6 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
        //      or using a separate command thread
        recordTrack->mState = TrackBase::STARTING_1;
        mActiveTracks.add(recordTrack);
        mActiveTracksGen++;
        status_t status = NO_ERROR;
        if (recordTrack->isExternalTrack()) {
            mLock.unlock();
@@ -6744,7 +6689,6 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
            // FIXME should verify that recordTrack is still in mActiveTracks
            if (status != NO_ERROR) {
                mActiveTracks.remove(recordTrack);
                mActiveTracksGen++;
                recordTrack->clearSyncStartEvent();
                ALOGV("RecordThread::start error %d", status);
                return status;
+97 −13
Original line number Diff line number Diff line
@@ -400,11 +400,10 @@ protected:
                    effect_uuid_t mType;    // effect type UUID
                };

                void        acquireWakeLock(int uid = -1);
                virtual void acquireWakeLock_l(int uid = -1);
                void        acquireWakeLock();
                virtual void acquireWakeLock_l();
                void        releaseWakeLock();
                void        releaseWakeLock_l();
                void        updateWakeLockUids(const SortedVector<int> &uids);
                void        updateWakeLockUids_l(const SortedVector<int> &uids);
                void        getPowerManager_l();
                void setEffectSuspended_l(const effect_uuid_t *type,
@@ -479,8 +478,88 @@ protected:
                static const size_t     kLogSize = 4 * 1024;
                sp<NBLog::Writer>       mNBLogWriter;
                bool                    mSystemReady;
                bool                    mNotifiedBatteryStart;
                ExtendedTimestamp       mTimestamp;

                // ActiveTracks is a sorted vector of track type T representing the
                // active tracks of threadLoop() to be considered by the locked prepare portion.
                // ActiveTracks should be accessed with the ThreadBase lock held.
                //
                // During processing and I/O, the threadLoop does not hold the lock;
                // hence it does not directly use ActiveTracks.  Care should be taken
                // to hold local strong references or defer removal of tracks
                // if the threadLoop may still be accessing those tracks due to mix, etc.
                //
                // This class updates power information appropriately.
                //

                template <typename T>
                class ActiveTracks {
                public:
                    ActiveTracks()
                        : mActiveTracksGeneration(0)
                        , mLastActiveTracksGeneration(0)
                    { }

                    ~ActiveTracks() {
                        clear();
                    }
                    // returns the last track added (even though it may have been
                    // subsequently removed from ActiveTracks).
                    //
                    // Used for DirectOutputThread to ensure a flush is called when transitioning
                    // to a new track (even though it may be on the same session).
                    // Used for OffloadThread to ensure that volume and mixer state is
                    // taken from the latest track added.
                    //
                    // The latest track is saved with a weak pointer to prevent keeping an
                    // otherwise useless track alive. Thus the function will return nullptr
                    // if the latest track has subsequently been removed and destroyed.
                    sp<T> getLatest() {
                        return mLatestActiveTrack.promote();
                    }

                    // Updates ActiveTracks client uids to the thread wakelock.
                    void updateWakeLockUids(sp<ThreadBase> thread, bool force = false) {
                        if (mActiveTracksGeneration != mLastActiveTracksGeneration || force) {
                            thread->updateWakeLockUids_l(getWakeLockUids());
                            mLastActiveTracksGeneration = mActiveTracksGeneration;
                        }
                    }

                    // SortedVector methods
                    ssize_t         add(const sp<T> &track);
                    ssize_t         remove(const sp<T> &track);
                    size_t          size() const {
                        return mActiveTracks.size();
                    }
                    ssize_t         indexOf(const sp<T>& item) {
                        return mActiveTracks.indexOf(item);
                    }
                    sp<T>           operator[](size_t index) const {
                        return mActiveTracks[index];
                    }
                    typename SortedVector<sp<T>>::iterator begin() {
                        return mActiveTracks.begin();
                    }
                    typename SortedVector<sp<T>>::iterator end() {
                        return mActiveTracks.end();
                    }
                    void            clear();

                private:
                    SortedVector<int> getWakeLockUids() {
                        SortedVector<int> wakeLockUids;
                        for (const sp<T> &track : mActiveTracks) {
                            wakeLockUids.add(track->uid());
                        }
                        return wakeLockUids; // moved by underlying SharedBuffer
                    }

                    SortedVector<sp<T>> mActiveTracks;
                    int                 mActiveTracksGeneration;
                    int                 mLastActiveTracksGeneration;
                    wp<T>               mLatestActiveTrack; // latest track added to ActiveTracks
                };
};

// --- PlaybackThread ---
@@ -559,6 +638,10 @@ protected:
    virtual     void        preExit();

    virtual     bool        keepWakeLock() const { return true; }
    virtual     void        acquireWakeLock_l() {
                                ThreadBase::acquireWakeLock_l();
                                mActiveTracks.updateWakeLockUids(this, true /* force */);
                            }

public:

@@ -731,10 +814,7 @@ private:
    bool                            mMasterMute;
                void        setMasterMute_l(bool muted) { mMasterMute = muted; }
protected:
    SortedVector< wp<Track> >       mActiveTracks;  // FIXME check if this could be sp<>
    SortedVector<int>               mWakeLockUids;
    int                             mActiveTracksGeneration;
    wp<Track>                       mLatestActiveTrack; // latest track added to mActiveTracks
    ActiveTracks<Track>     mActiveTracks;

    // Allocate a track name for a given channel mask.
    //   Returns name >= 0 if successful, -1 on failure.
@@ -900,8 +980,8 @@ protected:
    virtual     uint32_t    suspendSleepTimeUs() const;
    virtual     void        cacheParameters_l();

    virtual void acquireWakeLock_l(int uid = -1) {
        PlaybackThread::acquireWakeLock_l(uid);
    virtual void acquireWakeLock_l() {
        PlaybackThread::acquireWakeLock_l();
        if (hasFastMixer()) {
            mFastMixer->setBoottimeOffset(
                    mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME]);
@@ -1340,6 +1420,11 @@ public:
    virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                   audio_session_t sessionId);

    virtual void        acquireWakeLock_l() {
                            ThreadBase::acquireWakeLock_l();
                            mActiveTracks.updateWakeLockUids(this, true /* force */);
                        }

private:
            // Enter standby if not already in standby, and set mStandby flag
            void    standbyIfNotAlreadyInStandby();
@@ -1351,9 +1436,8 @@ private:
            SortedVector < sp<RecordTrack> >    mTracks;
            // mActiveTracks has dual roles:  it indicates the current active track(s), and
            // is used together with mStartStopCond to indicate start()/stop() progress
            SortedVector< sp<RecordTrack> >     mActiveTracks;
            // generation counter for mActiveTracks
            int                                 mActiveTracksGen;
            ActiveTracks<RecordTrack>           mActiveTracks;

            Condition                           mStartStopCond;

            // resampler converts input at HAL Hz to output at AudioRecord client Hz