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

Commit b27c97ac authored by Nader Jawad's avatar Nader Jawad Committed by Automerger Merge Worker
Browse files

Merge "Fix memory leak with RenderNodeAnimator" into tm-dev am: b9a8ed8b

parents bf0d76e7 b9a8ed8b
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -21170,6 +21170,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        }
        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId());
        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId());
        if (mBackgroundRenderNode != null) {
            mBackgroundRenderNode.forceEndAnimators();
        }
        mRenderNode.forceEndAnimators();
    }
    }
    private void cleanupDraw() {
    private void cleanupDraw() {
+49 −0
Original line number Original line Diff line number Diff line
@@ -19,17 +19,24 @@ package android.view;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNull;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.Activity;
import android.content.Context;
import android.content.Context;
import android.widget.FrameLayout;


import androidx.test.InstrumentationRegistry;
import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.rule.ActivityTestRule;


import org.junit.Assert;
import org.junit.Rule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.Test;


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@MediumTest
@MediumTest
public class RenderNodeAnimatorTest  {
public class RenderNodeAnimatorTest  {
    @Rule
    @Rule
@@ -57,4 +64,46 @@ public class RenderNodeAnimatorTest {
        anim.start(); // should initialize mTransformationInfo
        anim.start(); // should initialize mTransformationInfo
        assertNotNull(view.mTransformationInfo);
        assertNotNull(view.mTransformationInfo);
    }
    }

    @Test
    public void testViewDetachCancelsRenderNodeAnimator() {
        // Start a RenderNodeAnimator with a long duration time, then detach the target view
        // before the animation completes. Detaching of a View from a window should force cancel all
        // RenderNodeAnimators
        CountDownLatch latch = new CountDownLatch(1);

        FrameLayout container = new FrameLayout(getContext());
        View view = new View(getContext());

        getActivity().runOnUiThread(() -> {
            container.addView(view, new FrameLayout.LayoutParams(100, 100));
            getActivity().setContentView(container);
        });
        getActivity().runOnUiThread(() -> {
            RenderNodeAnimator anim = new RenderNodeAnimator(0, 0, 10f, 30f);
            anim.setDuration(10000);
            anim.setTarget(view);
            anim.addListener(new AnimatorListenerAdapter() {

                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    latch.countDown();
                }
            });

            anim.start();
        });

        getActivity().runOnUiThread(()-> {
            container.removeView(view);
        });

        try {
            Assert.assertTrue("onAnimationEnd not invoked",
                    latch.await(3000, TimeUnit.MILLISECONDS));
        } catch (InterruptedException excep) {
            Assert.fail("Interrupted waiting for onAnimationEnd callback");
        }
    }
}
}
+7 −0
Original line number Original line Diff line number Diff line
@@ -1611,6 +1611,11 @@ public final class RenderNode {
        nEndAllAnimators(mNativeRenderNode);
        nEndAllAnimators(mNativeRenderNode);
    }
    }


    /** @hide */
    public void forceEndAnimators() {
        nForceEndAnimators(mNativeRenderNode);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // Regular JNI methods
    // Regular JNI methods
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
@@ -1633,6 +1638,8 @@ public final class RenderNode {


    private static native void nEndAllAnimators(long renderNode);
    private static native void nEndAllAnimators(long renderNode);


    private static native void nForceEndAnimators(long renderNode);

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // @CriticalNative methods
    // @CriticalNative methods
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
+16 −3
Original line number Original line Diff line number Diff line
@@ -31,7 +31,8 @@ static void detach(sp<BaseRenderNodeAnimator>& animator) {
    animator->detach();
    animator->detach();
}
}


AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
AnimatorManager::AnimatorManager(RenderNode& parent)
        : mParent(parent), mAnimationHandle(nullptr), mCancelAllAnimators(false) {}


AnimatorManager::~AnimatorManager() {
AnimatorManager::~AnimatorManager() {
    for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
    for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
@@ -82,10 +83,18 @@ void AnimatorManager::pushStaging() {
        }
        }
        mNewAnimators.clear();
        mNewAnimators.clear();
    }
    }

    if (mCancelAllAnimators) {
        for (auto& animator : mAnimators) {
            animator->forceEndNow(mAnimationHandle->context());
        }
        mCancelAllAnimators = false;
    } else {
        for (auto& animator : mAnimators) {
        for (auto& animator : mAnimators) {
            animator->pushStaging(mAnimationHandle->context());
            animator->pushStaging(mAnimationHandle->context());
        }
        }
    }
    }
}


void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
    LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
    LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
@@ -184,5 +193,9 @@ void AnimatorManager::endAllActiveAnimators() {
    mAnimationHandle->release();
    mAnimationHandle->release();
}
}


void AnimatorManager::forceEndAnimators() {
    mCancelAllAnimators = true;
}

} /* namespace uirenderer */
} /* namespace uirenderer */
} /* namespace android */
} /* namespace android */
+6 −2
Original line number Original line Diff line number Diff line
@@ -16,11 +16,11 @@
#ifndef ANIMATORMANAGER_H
#ifndef ANIMATORMANAGER_H
#define ANIMATORMANAGER_H
#define ANIMATORMANAGER_H


#include <vector>

#include <cutils/compiler.h>
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
#include <utils/StrongPointer.h>


#include <vector>

#include "utils/Macros.h"
#include "utils/Macros.h"


namespace android {
namespace android {
@@ -56,6 +56,8 @@ public:
    // Hard-ends all animators. May only be called on the UI thread.
    // Hard-ends all animators. May only be called on the UI thread.
    void endAllStagingAnimators();
    void endAllStagingAnimators();


    void forceEndAnimators();

    // Hard-ends all animators that have been pushed. Used for cleanup if
    // Hard-ends all animators that have been pushed. Used for cleanup if
    // the ActivityContext is being destroyed
    // the ActivityContext is being destroyed
    void endAllActiveAnimators();
    void endAllActiveAnimators();
@@ -71,6 +73,8 @@ private:
    // To improve the efficiency of resizing & removing from the vector
    // To improve the efficiency of resizing & removing from the vector
    std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
    std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
    std::vector<sp<BaseRenderNodeAnimator> > mAnimators;
    std::vector<sp<BaseRenderNodeAnimator> > mAnimators;

    bool mCancelAllAnimators;
};
};


} /* namespace uirenderer */
} /* namespace uirenderer */
Loading