InsetController: Release leashes from RenderThread

We handle changes to the leashes from the UI thread, but use
the same SurfaceControl wrapper object from the RenderThread with
SyncRtSurfaceTransactionApplier. This means that at the time
we release a SurfaceControl from the UI thread we might have already
scheduled a SyncRtSurfaceTransactionApplier to use it, and actually
that could be in the process of running, leading to racy access and
crashes. To fix this we release the SurfaceControl from the RenderThread
so that it happens behind all existing operations.

Bug: 151086678
Test: Existing tests pass.
Change-Id: I2308d1c64f3f368c32587f99ddfb9e05955f821f
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 573d8fc..f52960c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -992,4 +992,23 @@
         }
         return mViewRoot.mWindowAttributes.insetsFlags.behavior;
     }
+
+    /**
+     * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
+     * setControl) we need to release the old leash. But we may have already scheduled
+     * a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid
+     * synchronization issues we also release from the RenderThread so this release
+     * happens after any existing items on the work queue.
+     */
+    public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+        if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) {
+            mViewRoot.registerRtFrameCallback(frame -> {
+                  sc.release();
+            });
+            // Make sure a frame gets scheduled.
+            mViewRoot.mView.invalidate();
+        } else {
+              sc.release();
+        }
+    }
 }
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index f07f1ce..252fc0c 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -117,7 +117,7 @@
             }
         }
         if (lastControl != null) {
-            lastControl.release();
+            lastControl.release(mController);
         }
     }
 
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 29ba56a..75f6eab 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -94,9 +94,9 @@
         dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
     }
 
-    public void release() {
+    public void release(InsetsController controller) {
         if (mLeash != null) {
-            mLeash.release();
+            controller.releaseSurfaceControlFromRt(mLeash);
         }
     }