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

Commit a7b50f8b authored by Szabolcs Vrbos's avatar Szabolcs Vrbos Committed by Steve Kondik
Browse files

Fix for cleaning up audio tracks of killed processes

A detailed description of the problem this patch fixes can be found here:
http://groups.google.com/group/android-developers/browse_thread/thread/6986d93003f86fb3

Change-Id: I1eab5263871277cab5feae4eae71ff2b5cfc34f8
parent 3ec3f5de
Loading
Loading
Loading
Loading
+60 −18
Original line number Diff line number Diff line
@@ -641,8 +641,10 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)

    sp<IBinder> binder = client->asBinder();
    if (mNotificationClients.indexOf(binder) < 0) {
        LOGV("Adding notification client %p", binder.get());
        binder->linkToDeath(this);
        LOGV("Adding notification client %p, and registering a new Grave DeathReceiver", binder.get());
        sp<Grave> aGrave = new Grave(this, IPCThreadState::self()->getCallingPid());
        binder->linkToDeath(aGrave);
        mGraveyard.add(aGrave);
        mNotificationClients.add(binder);
    }

@@ -657,22 +659,6 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
    }
}

void AudioFlinger::binderDied(const wp<IBinder>& who) {

    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
    Mutex::Autolock _l(mLock);

    IBinder *binder = who.unsafe_get();

    if (binder != NULL) {
        int index = mNotificationClients.indexOf(binder);
        if (index >= 0) {
            LOGV("Removing notification client %p", binder);
            mNotificationClients.removeAt(index);
        }
    }
}

// audioConfigChanged_l() must be called with AudioFlinger::mLock held
void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) {
    size_t size = mNotificationClients.size();
@@ -2919,6 +2905,62 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const

// ----------------------------------------------------------------------------

AudioFlinger::Grave::Grave(const sp<AudioFlinger>& audioFlinger, pid_t pid)
    :   mAudioFlinger(audioFlinger),
        mPid(pid)
{
}

void AudioFlinger::Grave::binderDied(const wp<IBinder>& who)
{
    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
    Mutex::Autolock _l(mAudioFlinger->mLock);

    // holding a list of tracks to destory (avoiding modification of AF::MT::mTracks while iterating it)
    SortedVector< wp<MixerThread::Track> > tracksToRemove;

    for (size_t i = 0; i < mAudioFlinger->mPlaybackThreads.size(); i++) {
        PlaybackThread *thread = mAudioFlinger->mPlaybackThreads.valueAt(i).get();

        for (size_t i=0; i<thread->mActiveTracks.size(); i++) {
            wp<MixerThread::Track> wtrack = thread->mActiveTracks[i];
            sp<MixerThread::Track> strack = wtrack.unsafe_get();
            if (strack != NULL && strack->mClient->pid() == mPid) {
                tracksToRemove.add(wtrack);
            }
        }

        // remove all the tracks that need to be...
        size_t count = tracksToRemove.size();
        if (UNLIKELY(count)) {
            for (size_t i=0 ; i<count ; i++) {
                const sp<MixerThread::Track>& track = tracksToRemove[i].promote();
                thread->mActiveTracks.remove(track);
                if (track->isTerminated()) {
                    thread->mTracks.remove(track);
                    thread->deleteTrackName_l(track->mName);
                }
            }
        }

        tracksToRemove.clear();
    }

    IBinder *binder = who.unsafe_get();

    if (binder != NULL) {
        int index = mAudioFlinger->mNotificationClients.indexOf(binder);
        if (index >= 0) {
            LOGV("Removing notification client %p", binder);
            mAudioFlinger->mNotificationClients.removeAt(index);
        }
    }

    mAudioFlinger->mGraveyard.remove(this);
}

// ----------------------------------------------------------------------------

AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
    : BnAudioTrack(),
      mTrack(track)
+19 −4
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ class AudioResampler;

static const nsecs_t kStandbyTimeInNsecs = seconds(3);

class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
class AudioFlinger : public BnAudioFlinger
{
public:
    static void instantiate();
@@ -136,9 +136,6 @@ public:

    virtual status_t setVoiceVolume(float volume);

    // IBinder::DeathRecipient
    virtual     void        binderDied(const wp<IBinder>& who);

    enum hardware_call_state {
        AUDIO_HW_IDLE = 0,
        AUDIO_HW_INIT,
@@ -202,6 +199,23 @@ private:
        pid_t               mPid;
    };

    // --- Grave ---
    // Enabling Track stopping/cleanup of active tracks belonging to killed processes.
    // Not using Client above, since mClients contains WeakPointers, while mGraveyard needs
    // StrongPointers, otherwise the IBinder::binderDied callback is never called.
    // Alternatively, Client above could have been made to implement DeathRecipient,
    // while changing mClients to be sp<> instead of wp<>. However, I dont feel qualified
    // enough to make this change (not sure about how/when clients in that list are
    // removed/destroyed).
    class Grave : public IBinder::DeathRecipient {
    public:
                            Grave(const sp<AudioFlinger>& audioFlinger, pid_t pid);
            virtual void    binderDied(const wp<IBinder>& who); // IBinder::DeathRecipient
    private:
            sp<AudioFlinger>    mAudioFlinger;
            pid_t               mPid;
    };


    class TrackHandle;
    class RecordHandle;
@@ -778,6 +792,7 @@ private:
    mutable     Mutex                               mLock;

                DefaultKeyedVector< pid_t, wp<Client> >     mClients;
                SortedVector< sp<Grave> >           mGraveyard;

                mutable     Mutex                   mHardwareLock;
                AudioHardwareInterface*             mAudioHardware;