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

Commit 435fa67f authored by Daniel Norman's avatar Daniel Norman
Browse files

Perform magnification viewport drawing outside of WM global lock.

Attempts to fix the deadlock caused by holding onto the WM global lock
too long.

Bug: 276845499
Test: Use magnification, observe no change in behavior
Test: Existing magnification-related tests:
       atest frameworks/base/services/tests/servicestests/ \
         src/com/android/server/accessibility/magnification
       atest frameworks/base/packages/SystemUI/tests/ \
         src/com/android/systemui/accessibility
       atest cts/tests/accessibilityservice/ \
         src/android/accessibilityservice/cts
Merged-In: Id828744c8c5bcb4bdb3be9a11810338614b84b2e
Change-Id: Id828744c8c5bcb4bdb3be9a11810338614b84b2e
(cherry picked from commit 6ae1113e)
parent 1af69bd9
Loading
Loading
Loading
Loading
+37 −29
Original line number Diff line number Diff line
@@ -1280,46 +1280,54 @@ final class AccessibilityController {
                }

                void drawIfNeeded(SurfaceControl.Transaction t) {
                    // Drawing variables (alpha, dirty rect, and bounds) access is synchronized
                    // using WindowManagerGlobalLock. Grab copies of these values before
                    // drawing on the canvas so that drawing can be performed outside of the lock.
                    int alpha;
                    Rect drawingRect = null;
                    Region drawingBounds = null;
                    synchronized (mService.mGlobalLock) {
                        if (!mInvalidated) {
                            return;
                        }
                        mInvalidated = false;
                        if (mAlpha > 0) {
                            Canvas canvas = null;
                            try {

                        alpha = mAlpha;
                        if (alpha > 0) {
                            drawingBounds = new Region(mBounds);
                            // Empty dirty rectangle means unspecified.
                            if (mDirtyRect.isEmpty()) {
                                mBounds.getBounds(mDirtyRect);
                            }
                            mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
                                canvas = mSurface.lockCanvas(mDirtyRect);
                            drawingRect = new Rect(mDirtyRect);
                            if (DEBUG_VIEWPORT_WINDOW) {
                                    Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
                                Slog.i(LOG_TAG, "ViewportWindow bounds: " + mBounds);
                                Slog.i(LOG_TAG, "ViewportWindow dirty rect: " + mDirtyRect);
                            }
                            } catch (IllegalArgumentException iae) {
                                /* ignore */
                            } catch (Surface.OutOfResourcesException oore) {
                        }
                    }

                    // Draw without holding WindowManagerGlobalLock.
                    if (alpha > 0) {
                        Canvas canvas = null;
                        try {
                            canvas = mSurface.lockCanvas(drawingRect);
                        } catch (IllegalArgumentException | OutOfResourcesException e) {
                            /* ignore */
                        }
                        if (canvas == null) {
                            return;
                        }
                            if (DEBUG_VIEWPORT_WINDOW) {
                                Slog.i(LOG_TAG, "Bounds: " + mBounds);
                            }
                        canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
                            mPaint.setAlpha(mAlpha);
                            Path path = mBounds.getBoundaryPath();
                            canvas.drawPath(path, mPaint);

                        mPaint.setAlpha(alpha);
                        canvas.drawPath(drawingBounds.getBoundaryPath(), mPaint);
                        mSurface.unlockCanvasAndPost(canvas);
                        t.show(mSurfaceControl);
                    } else {
                        t.hide(mSurfaceControl);
                    }
                }
                }

                void releaseSurface() {
                    if (mBlastBufferQueue != null) {