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

Commit ad30f958 authored by Robert Carr's avatar Robert Carr
Browse files

Null AppWindowThumbnail SurfaceControl after releasing it.

Otherwise SurfaceAnimator#reset may try and use it and throw an unhandled
exception. It looks like this should be safe because we always null the
SurfaceAnimator after releasing it's surface. The only other point holding
on to the surface should be the animator, and the animator properly checks
for null.

Bug: 124877830
Test: AppWindowThumbnailTest
Change-Id: I3841b27cc9e24ed24951df27b2b35a22bca70130
parent 53cc8bf1
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ class AppWindowThumbnail implements Animatable {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowThumbnail" : TAG_WM;

    private final AppWindowToken mAppToken;
    private final SurfaceControl mSurfaceControl;
    private SurfaceControl mSurfaceControl;
    private final SurfaceAnimator mSurfaceAnimator;
    private final int mWidth;
    private final int mHeight;
@@ -68,10 +68,21 @@ class AppWindowThumbnail implements Animatable {
     */
    AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader,
            boolean relative) {
        this(t, appToken, thumbnailHeader, relative, new Surface(), null);
    }

    AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader,
            boolean relative, Surface drawSurface, SurfaceAnimator animator) {
        mAppToken = appToken;
        mRelative = relative;
        if (animator != null) {
            mSurfaceAnimator = animator;
        } else {
            // We can't use a delegating constructor since we need to
            // reference this::onAnimationFinished
            mSurfaceAnimator =
                new SurfaceAnimator(this, this::onAnimationFinished, appToken.mWmService);
        }
        mWidth = thumbnailHeader.getWidth();
        mHeight = thumbnailHeader.getHeight();

@@ -95,7 +106,6 @@ class AppWindowThumbnail implements Animatable {
        }

        // Transfer the thumbnail to the surface
        Surface drawSurface = new Surface();
        drawSurface.copyFrom(mSurfaceControl);
        drawSurface.attachAndQueueBuffer(thumbnailHeader);
        drawSurface.release();
@@ -145,6 +155,7 @@ class AppWindowThumbnail implements Animatable {
    void destroy() {
        mSurfaceAnimator.cancelAnimation();
        getPendingTransaction().remove(mSurfaceControl);
        mSurfaceControl = null;
    }

    /**
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
import android.view.SurfaceControl;

import androidx.test.filters.SmallTest;

import org.junit.Test;

/**
 * Test class for {@link TaskSnapshotSurface}.
 *
 * Build/Install/Run:
 *  atest FrameworksServicesTest:AppWindowThumbnailTest
 *
 */
@SmallTest
@Presubmit
public class AppWindowThumbnailTest extends WindowTestsBase {
    private AppWindowThumbnail buildThumbnail() {
        final GraphicBuffer buffer = GraphicBuffer.create(1, 1, PixelFormat.RGBA_8888,
                GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER);
        final AppWindowToken mockAwt = mock(AppWindowToken.class);
        when(mockAwt.getPendingTransaction()).thenReturn(new StubTransaction());
        when(mockAwt.makeSurface()).thenReturn(new MockSurfaceControlBuilder());
        return new AppWindowThumbnail(new StubTransaction(), mockAwt,
                buffer, false, mock(Surface.class), mock(SurfaceAnimator.class));
    }

    @Test
    public void testDestroy_nullsSurface() {
        final AppWindowThumbnail t = buildThumbnail();
        assertNotNull(t.getSurfaceControl());
        t.destroy();
        assertNull(t.getSurfaceControl());
    }
}