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

Commit bd6dc464 authored by zengjing's avatar zengjing Committed by Mikhail Naganov
Browse files

Visualizer: fix native crash when visualizer release



When the Visualizer effect is released, synchronous wait for the CaptureThread can
cause ANR in an app. This is why an asynchronous 'release' method is introduced which
is used by Visualizer.release() method on the Java side. Since CaptureThread may still
be running while the the last reference to the Visualizer instance is released,
CaptureThread now holds a strong reference to the Visualizer, which it releases
upon exit from the thread loop.

The 'release' method does not check for 'enabled' status because setEnabled(false)
may fail due to audioserver calling AudioFlinger::EffectHandle::setControl to
hold control.

Bug: 124833084
Test: CTS VisualizerTest
Change-Id: I8d936f0f79540345d3e3675f6129bb942a08e423
Merged-In: I8d936f0f79540345d3e3675f6129bb942a08e423
Signed-off-by: default avatarzengjing <zengjing@xiaomi.com>
parent a504d888
Loading
Loading
Loading
Loading
+20 −3
Original line number Original line Diff line number Diff line
@@ -56,6 +56,19 @@ Visualizer::~Visualizer()
    setCaptureCallBack(NULL, NULL, 0, 0);
    setCaptureCallBack(NULL, NULL, 0, 0);
}
}


void Visualizer::release()
{
    ALOGV("Visualizer::release()");
    setEnabled(false);
    Mutex::Autolock _l(mCaptureLock);

    mCaptureThread.clear();
    mCaptureCallBack = NULL;
    mCaptureCbkUser = NULL;
    mCaptureFlags = 0;
    mCaptureRate = 0;
}

status_t Visualizer::setEnabled(bool enabled)
status_t Visualizer::setEnabled(bool enabled)
{
{
    Mutex::Autolock _l(mCaptureLock);
    Mutex::Autolock _l(mCaptureLock);
@@ -115,7 +128,7 @@ status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t
    mCaptureRate = rate;
    mCaptureRate = rate;


    if (cbk != NULL) {
    if (cbk != NULL) {
        mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
        mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
    }
    }
    ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
    ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
            rate, mCaptureThread.get(), mCaptureFlags);
            rate, mCaptureThread.get(), mCaptureFlags);
@@ -402,7 +415,7 @@ void Visualizer::controlStatusChanged(bool controlGranted) {


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


Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate,
Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
        bool bCanCallJava)
        bool bCanCallJava)
    : Thread(bCanCallJava), mReceiver(receiver)
    : Thread(bCanCallJava), mReceiver(receiver)
{
{
@@ -413,10 +426,14 @@ Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureR
bool Visualizer::CaptureThread::threadLoop()
bool Visualizer::CaptureThread::threadLoop()
{
{
    ALOGV("CaptureThread %p enter", this);
    ALOGV("CaptureThread %p enter", this);
    sp<Visualizer> receiver = mReceiver.promote();
    if (receiver == NULL) {
        return false;
    }
    while (!exitPending())
    while (!exitPending())
    {
    {
        usleep(mSleepTimeUs);
        usleep(mSleepTimeUs);
        mReceiver.periodicCapture();
        receiver->periodicCapture();
    }
    }
    ALOGV("CaptureThread %p exiting", this);
    ALOGV("CaptureThread %p exiting", this);
    return false;
    return false;
+3 −2
Original line number Original line Diff line number Diff line
@@ -131,6 +131,7 @@ public:
    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
    // are returned
    // are returned
    status_t getFft(uint8_t *fft);
    status_t getFft(uint8_t *fft);
    void release();


protected:
protected:
    // from IEffectClient
    // from IEffectClient
@@ -146,12 +147,12 @@ private:
    class CaptureThread : public Thread
    class CaptureThread : public Thread
    {
    {
    public:
    public:
        CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava = false);
        CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);


    private:
    private:
        friend class Visualizer;
        friend class Visualizer;
        virtual bool        threadLoop();
        virtual bool        threadLoop();
        Visualizer& mReceiver;
        wp<Visualizer> mReceiver;
        Mutex       mLock;
        Mutex       mLock;
        uint32_t mSleepTimeUs;
        uint32_t mSleepTimeUs;
    };
    };