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

Commit ec9f4563 authored by Ram Indani's avatar Ram Indani Committed by Android (Google) Code Review
Browse files

Merge changes I7167e29d,I1b48c892,Ic6b27d38

* changes:
  Use NativeAllocationRegistry for DisplayEventReceiver
  Use camel case to name the tests Rearrange SurfaceHolder callback methods
  Update the Attached Choreographer test to use divisor for refresh rate
parents aeeff9a2 1585f199
Loading
Loading
Loading
Loading
+12 −15
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import com.android.internal.annotations.VisibleForTesting;

import dalvik.annotation.optimization.FastNative;

import libcore.util.NativeAllocationRegistry;

import java.lang.ref.WeakReference;

/**
@@ -81,11 +83,17 @@ public abstract class DisplayEventReceiver {

    private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
            MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle);
    private static native void nativeDispose(long receiverPtr);
    private static native long nativeGetDisplayEventReceiverFinalizer();
    @FastNative
    private static native void nativeScheduleVsync(long receiverPtr);
    private static native VsyncEventData nativeGetLatestVsyncEventData(long receiverPtr);

    private static final NativeAllocationRegistry sNativeAllocationRegistry =
            NativeAllocationRegistry.createMalloced(
                    DisplayEventReceiver.class.getClassLoader(),
                    nativeGetDisplayEventReceiverFinalizer());
    private Runnable mFreeNativeResources;

    /**
     * Creates a display event receiver.
     *
@@ -118,27 +126,16 @@ public abstract class DisplayEventReceiver {
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource, eventRegistration, layerHandle);
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            dispose(true);
        } finally {
            super.finalize();
        }
        mFreeNativeResources = sNativeAllocationRegistry.registerNativeAllocation(this,
                mReceiverPtr);
    }

    /**
     * Disposes the receiver.
     */
    public void dispose() {
        dispose(false);
    }

    private void dispose(boolean finalized) {
        if (mReceiverPtr != 0) {
            nativeDispose(mReceiverPtr);
            mFreeNativeResources.run();
            mReceiverPtr = 0;
        }
        mMessageQueue = null;
+0 −1
Original line number Diff line number Diff line
@@ -1386,7 +1386,6 @@ public final class SurfaceControl implements Parcelable {
            synchronized (mChoreographerLock) {
                if (mChoreographer != null) {
                    mChoreographer.invalidate();
                    // TODO(b/266121235): Use NativeAllocationRegistry to clean up Choreographer.
                    mChoreographer = null;
                }
            }
+7 −4
Original line number Diff line number Diff line
@@ -240,13 +240,15 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject
    return reinterpret_cast<jlong>(receiver.get());
}

static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    NativeDisplayEventReceiver* receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
static void release(NativeDisplayEventReceiver* receiver) {
    receiver->dispose();
    receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
}

static jlong nativeGetDisplayEventReceiverFinalizer(JNIEnv*, jclass) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&release));
}

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
@@ -274,7 +276,8 @@ static const JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        {"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;IIJ)J",
         (void*)nativeInit},
        {"nativeDispose", "(J)V", (void*)nativeDispose},
        {"nativeGetDisplayEventReceiverFinalizer", "()J",
         (void*)nativeGetDisplayEventReceiverFinalizer},
        // @FastNative
        {"nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync},
        {"nativeGetLatestVsyncEventData", "(J)Landroid/view/DisplayEventReceiver$VsyncEventData;",
+42 −61
Original line number Diff line number Diff line
@@ -50,16 +50,13 @@ import java.util.concurrent.TimeUnit;
public class AttachedChoreographerTest {
    private static final String TAG = "AttachedChoreographerTest";
    private static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID = 170503758;
    private static final int THRESHOLD_MS = 10;
    private static final int CALLBACK_TIME_10_FPS = 100;
    private static final int CALLBACK_TIME_30_FPS = 33;
    private static final long THRESHOLD_MS = 10;
    private static final int FRAME_ITERATIONS = 21;
    private static final int CALLBACK_MISSED_THRESHOLD = 2;

    private final CountDownLatch mTestCompleteSignal = new CountDownLatch(2);
    private final CountDownLatch mSurfaceCreationCountDown = new CountDownLatch(1);
    private final CountDownLatch mNoCallbackSignal = new CountDownLatch(1);
    private final CountDownLatch mFramesSignal = new CountDownLatch(FRAME_ITERATIONS);

    private ActivityScenario<GraphicsActivity> mScenario;
    private int mInitialMatchContentFrameRate;
@@ -73,20 +70,19 @@ public class AttachedChoreographerTest {
    public void setUp() throws Exception {
        mScenario = ActivityScenario.launch(GraphicsActivity.class);
        mScenario.moveToState(Lifecycle.State.CREATED);
        mCallbackMissedCounter = 0;
        mScenario.onActivity(activity -> {
            mSurfaceView = activity.findViewById(R.id.surface);
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width,
                        int height) {
                public void surfaceCreated(SurfaceHolder holder) {
                    mSurfaceCreationCountDown.countDown();
                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    mSurfaceCreationCountDown.countDown();
                public void surfaceChanged(SurfaceHolder holder, int format, int width,
                        int height) {
                }

                @Override
@@ -95,7 +91,6 @@ public class AttachedChoreographerTest {
            });
        });


        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        uiDevice.wakeUp();
        uiDevice.executeShellCommand("wm dismiss-keyguard");
@@ -131,7 +126,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_create_choreographer() {
    public void testCreateChoreographer() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -166,7 +161,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_copy_surface_control() {
    public void testCopySurfaceControl() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -199,7 +194,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_mirror_surface_control() {
    public void testMirrorSurfaceControl() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -231,7 +226,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_postFrameCallback() {
    public void testPostFrameCallback() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -256,7 +251,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_postFrameCallbackDelayed() {
    public void testPostFrameCallbackDelayed() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -283,7 +278,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_postCallback() {
    public void testPostCallback() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -309,7 +304,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_postCallbackDelayed() {
    public void testPostCallbackDelayed() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -335,7 +330,7 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_postVsyncCallback() {
    public void testPostVsyncCallback() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeout */ 1L)) {
                fail("Unable to create surface within 1 Second");
@@ -359,7 +354,9 @@ public class AttachedChoreographerTest {
    }

    @Test
    public void test_choreographer_10Hz_refreshRate() {
    public void testChoreographerDivisorRefreshRate() {
        for (int divisor : new int[]{2, 3}) {
            CountDownLatch continueLatch = new CountDownLatch(1);
            mScenario.onActivity(activity -> {
                if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                    fail("Unable to create surface within 1 Second");
@@ -367,44 +364,27 @@ public class AttachedChoreographerTest {
                SurfaceControl sc = mSurfaceView.getSurfaceControl();
                Choreographer choreographer = sc.getChoreographer();
                SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
            transaction.setFrameRate(sc, 10.0f, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
                float displayRefreshRate = activity.getDisplay().getMode().getRefreshRate();
                float fps = displayRefreshRate / divisor;
                long callbackDurationMs = Math.round(1000 / fps);
                mCallbackMissedCounter = 0;
                transaction.setFrameRate(sc, fps, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
                        .addTransactionCommittedListener(Runnable::run,
                                () -> verifyVsyncCallbacks(choreographer,
                                    CALLBACK_TIME_10_FPS))
                                        callbackDurationMs, continueLatch, FRAME_ITERATIONS))
                        .apply();
            mTestCompleteSignal.countDown();
            });
        if (waitForCountDown(mTestCompleteSignal, /* timeoutInSeconds */ 5L)) {
            // wait for the previous callbacks to finish before moving to the next divisor
            if (waitForCountDown(continueLatch, /* timeoutInSeconds */ 5L)) {
                fail("Test not finished in 5 Seconds");
            }
        }

    @Test
    public void test_choreographer_30Hz_refreshRate() {
        mScenario.onActivity(activity -> {
            if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
                fail("Unable to create surface within 1 Second");
            }
            SurfaceControl sc = mSurfaceView.getSurfaceControl();
            Choreographer choreographer = sc.getChoreographer();
            SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
            transaction.setFrameRate(sc, 30.0f, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
                    .addTransactionCommittedListener(Runnable::run,
                            () -> verifyVsyncCallbacks(choreographer,
                                    CALLBACK_TIME_30_FPS))
                    .apply();
            mTestCompleteSignal.countDown();
        });
        if (waitForCountDown(mTestCompleteSignal, /* timeoutInSeconds */ 5L)) {
            fail("Test not finished in 5 Seconds");
        }
    }

    private void verifyVsyncCallbacks(Choreographer choreographer, int callbackDurationMs) {
    private void verifyVsyncCallbacks(Choreographer choreographer, long callbackDurationMs,
            CountDownLatch continueLatch, int frameCount) {
        long callbackRequestedTimeNs = System.nanoTime();
        choreographer.postVsyncCallback(frameData -> {
            mFramesSignal.countDown();
            final long frameCount = mFramesSignal.getCount();
            if (frameCount > 0) {
                if (!mIsFirstCallback) {
                    // Skip the first callback as it takes 1 frame
@@ -422,18 +402,19 @@ public class AttachedChoreographerTest {
                    }
                }
                mIsFirstCallback = false;
                verifyVsyncCallbacks(choreographer, callbackDurationMs);
                verifyVsyncCallbacks(choreographer, callbackDurationMs,
                        continueLatch, frameCount - 1);
            } else {
                assertTrue("Missed timeline for " + mCallbackMissedCounter + " callbacks, while "
                                + CALLBACK_MISSED_THRESHOLD + " missed callbacks are allowed",
                        mCallbackMissedCounter <= CALLBACK_MISSED_THRESHOLD);
                mTestCompleteSignal.countDown();
                continueLatch.countDown();
            }
        });
    }

    private long getCallbackDurationDiffInMs(long callbackTimeNs, long requestedTimeNs,
            int expectedCallbackMs) {
            long expectedCallbackMs) {
        long actualTimeMs = TimeUnit.NANOSECONDS.toMillis(callbackTimeNs)
                - TimeUnit.NANOSECONDS.toMillis(requestedTimeNs);
        return Math.abs(expectedCallbackMs - actualTimeMs);