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

Commit 74c76039 authored by Robert Carr's avatar Robert Carr Committed by Rob Carr
Browse files

SurfaceView: Fix overlocking of mSurfaceLock

mSurfaceLock is used to ensure the Surface object stays valid over
the span of the calls to lockCanvas and unlockCanvasAndPost which could
come from any thread. In API Level 29 and below, updateSurface was
split in to two paths, a first path (which would acquire mSurfaceLock)
for when the Surface could be destroyed, and second path for geometry
updates only. The consolidation of these two paths in updateSurface
created an overlocking of mSurfaceLock, which is now acquired even
when mSurface won't be modified. In fact it's acquired whenever the
geometry changes. This means an application rendering thread which
creates delays between lock and unlock canvas could create undesirable
and needless delays on the main UI thread, if the SurfaceView geometry
updates. We also have some underlocking, where we aren't actually
locking when destroying the SurfaceView.

Test: Manual with test app
Bug: 206846658
Change-Id: Idc17d111eee7a7365af4e94a156e7c46c7ea8171
parent a4a4f42b
Loading
Loading
Loading
Loading
+112 −104
Original line number Diff line number Diff line
@@ -720,8 +720,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    private void releaseSurfaces(boolean releaseSurfacePackage) {
        mSurfaceAlpha = 1f;
	
        synchronized (mSurfaceControlLock) {
        mSurfaceLock.lock();
        try {
            mSurface.destroy();
        } finally {
            mSurfaceLock.unlock();
        }
        synchronized (mSurfaceControlLock) {
            if (mBlastBufferQueue != null) {
                mBlastBufferQueue.destroy();
                mBlastBufferQueue = null;
@@ -770,8 +775,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            Transaction surfaceUpdateTransaction) {
        boolean realSizeChanged = false;

        mSurfaceLock.lock();
        try {
        mDrawingStopped = !mVisible;

        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -811,7 +814,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            setBufferSize(surfaceUpdateTransaction);
        }
        if (sizeChanged || creating || !isHardwareAccelerated()) {

            // Set a window crop when creating the surface or changing its size to
            // crop the buffer to the surface size since the buffer producer may
            // use SCALING_MODE_SCALE and submit a larger size than the surface
@@ -849,7 +851,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        }
        applyTransactionOnVriDraw(surfaceUpdateTransaction);
        updateEmbeddedAccessibilityMatrix(false);

         mSurfaceFrame.left = 0;
        mSurfaceFrame.top = 0;
        if (translator == null) {
@@ -866,9 +867,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                || mLastSurfaceHeight != surfaceHeight;
        mLastSurfaceWidth = surfaceWidth;
        mLastSurfaceHeight = surfaceHeight;
        } finally {
            mSurfaceLock.unlock();
        }

        return realSizeChanged;
    }

@@ -1103,21 +1102,30 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
     *                          Surface for compatibility reasons.
     */
    private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) {
        if (surfaceControlCreated) {
            mSurface.copyFrom(mBlastBufferQueue);
        }

        if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.O) {
        // Some legacy applications use the underlying native {@link Surface} object
        // as a key to whether anything has changed. In these cases, updates to the
        // existing {@link Surface} will be ignored when the size changes.
        // Therefore, we must explicitly recreate the {@link Surface} in these
        // cases.
        boolean needsWorkaround = bufferSizeChanged &&
            getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O;
       if (!surfaceControlCreated && !needsWorkaround) {
           return;
       }
       mSurfaceLock.lock();
       try {
           if (surfaceControlCreated) {
               mSurface.copyFrom(mBlastBufferQueue);
           }

           if (needsWorkaround) {
               if (mBlastBufferQueue != null) {
                   mSurface.transferFrom(mBlastBufferQueue.createSurfaceWithHandle());
               }
           }
       } finally {
           mSurfaceLock.unlock();
       }
    }

    private void setBufferSize(Transaction transaction) {