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

Commit 481fb67a authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Add RecordThread media.log and deferred deallocation

This change allows a media.log buffer for RecordThread.

Unlike playback threads which stick around forever, the RecordThread comes
and goes for every capture session.  This means that the media.log buffer
for a RecordThread would disappear too, and so was useless.  Now when a
thread exits, it's associated media.log buffer is just marked for deferred
deallocation.  It is only actually freed when the memory is needed.

Other changes:
 - Fix bug in unregistering comparison, it was comparing the wrong pointers
 - Increased size of log area so we can log for RecordThread also

Change-Id: If45d4c03a793b86390a0112ec3acc5d41b2e3635
parent 84acd489
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -441,7 +441,7 @@ void NBLog::Reader::dump(int fd, size_t indent)


bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
{
{
    return iMemory.get() == mIMemory.get();
    return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
}
}


}   // namespace android
}   // namespace android
+49 −12
Original line number Original line Diff line number Diff line
@@ -213,6 +213,18 @@ AudioFlinger::~AudioFlinger()
        audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
        audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
        delete mAudioHwDevs.valueAt(i);
        delete mAudioHwDevs.valueAt(i);
    }
    }

    // Tell media.log service about any old writers that still need to be unregistered
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
    if (binder != 0) {
        sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
        for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
            sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
            mUnregisteredWriters.pop();
            mediaLogService->unregisterWriter(iMemory);
        }
    }

}
}


static const char * const audio_interfaces[] = {
static const char * const audio_interfaces[] = {
@@ -406,16 +418,44 @@ sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)


sp<NBLog::Writer> AudioFlinger::newWriter_l(size_t size, const char *name)
sp<NBLog::Writer> AudioFlinger::newWriter_l(size_t size, const char *name)
{
{
    // If there is no memory allocated for logs, return a dummy writer that does nothing
    if (mLogMemoryDealer == 0) {
    if (mLogMemoryDealer == 0) {
        return new NBLog::Writer();
        return new NBLog::Writer();
    }
    }
    sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
    sp<NBLog::Writer> writer = new NBLog::Writer(size, shared);
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
    if (binder != 0) {
    // Similarly if we can't contact the media.log service, also return a dummy writer
        interface_cast<IMediaLogService>(binder)->registerWriter(shared, size, name);
    if (binder == 0) {
        return new NBLog::Writer();
    }
    sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
    sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
    // If allocation fails, consult the vector of previously unregistered writers
    // and garbage-collect one or more them until an allocation succeeds
    if (shared == 0) {
        Mutex::Autolock _l(mUnregisteredWritersLock);
        for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
            {
                // Pick the oldest stale writer to garbage-collect
                sp<IMemory> iMemory(mUnregisteredWriters[0]->getIMemory());
                mUnregisteredWriters.removeAt(0);
                mediaLogService->unregisterWriter(iMemory);
                // Now the media.log remote reference to IMemory is gone.  When our last local
                // reference to IMemory also drops to zero at end of this block,
                // the IMemory destructor will deallocate the region from mLogMemoryDealer.
            }
            // Re-attempt the allocation
            shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
            if (shared != 0) {
                goto success;
            }
        }
        // Even after garbage-collecting all old writers, there is still not enough memory,
        // so return a dummy writer
        return new NBLog::Writer();
    }
    }
    return writer;
success:
    mediaLogService->registerWriter(shared, size, name);
    return new NBLog::Writer(size, shared);
}
}


void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
@@ -427,13 +467,10 @@ void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
    if (iMemory == 0) {
    if (iMemory == 0) {
        return;
        return;
    }
    }
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
    // Rather than removing the writer immediately, append it to a queue of old writers to
    if (binder != 0) {
    // be garbage-collected later.  This allows us to continue to view old logs for a while.
        interface_cast<IMediaLogService>(binder)->unregisterWriter(iMemory);
    Mutex::Autolock _l(mUnregisteredWritersLock);
        // Now the media.log remote reference to IMemory is gone.
    mUnregisteredWriters.push(writer);
        // When our last local reference to IMemory also drops to zero,
        // the IMemory destructor will deallocate the region from mMemoryDealer.
    }
}
}


// IAudioFlinger interface
// IAudioFlinger interface
+5 −1
Original line number Original line Diff line number Diff line
@@ -235,8 +235,12 @@ public:
    sp<NBLog::Writer>   newWriter_l(size_t size, const char *name);
    sp<NBLog::Writer>   newWriter_l(size_t size, const char *name);
    void                unregisterWriter(const sp<NBLog::Writer>& writer);
    void                unregisterWriter(const sp<NBLog::Writer>& writer);
private:
private:
    static const size_t kLogMemorySize = 10 * 1024;
    static const size_t kLogMemorySize = 40 * 1024;
    sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
    sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
    // When a log writer is unregistered, it is done lazily so that media.log can continue to see it
    // for as long as possible.  The memory is only freed when it is needed for another log writer.
    Vector< sp<NBLog::Writer> > mUnregisteredWriters;
    Mutex               mUnregisteredWritersLock;
public:
public:


    class SyncEvent;
    class SyncEvent;
+2 −0
Original line number Original line Diff line number Diff line
@@ -4404,6 +4404,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
#endif
#endif
{
{
    snprintf(mName, kNameLength, "AudioIn_%X", id);
    snprintf(mName, kNameLength, "AudioIn_%X", id);
    mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);


    readInputParameters();
    readInputParameters();
}
}
@@ -4411,6 +4412,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,


AudioFlinger::RecordThread::~RecordThread()
AudioFlinger::RecordThread::~RecordThread()
{
{
    mAudioFlinger->unregisterWriter(mNBLogWriter);
    delete[] mRsmpInBuffer;
    delete[] mRsmpInBuffer;
    delete mResampler;
    delete mResampler;
    delete[] mRsmpOutBuffer;
    delete[] mRsmpOutBuffer;