Clean up remote animation definitions when activity is destroyed

- Remove the remote animation definition when the associated process dies
- Also expose method to unregister any registered animation defs

Bug: 139137636
Test: Kill launcher, ensure the remote animation ref is removed
Change-Id: Ia38d037397703221c17c8258ec1a245055d5896d
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ff581c0..9e0c2fc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8674,7 +8674,6 @@
      * @hide
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
-    @UnsupportedAppUsage
     public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
         try {
             ActivityTaskManager.getService().registerRemoteAnimations(mToken, definition);
@@ -8683,6 +8682,20 @@
         }
     }
 
+    /**
+     * Unregisters all remote animations for this activity.
+     *
+     * @hide
+     */
+    @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
+    public void unregisterRemoteAnimations() {
+        try {
+            ActivityTaskManager.getService().unregisterRemoteAnimations(mToken);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     class HostCallbacks extends FragmentHostCallback<Activity> {
         public HostCallbacks() {
             super(Activity.this /*activity*/);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index e2b1b86..df5d6c7 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -437,6 +437,11 @@
     void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
 
     /**
+     * Unregisters all remote animations for a specific activity.
+     */
+    void unregisterRemoteAnimations(in IBinder token);
+
+    /**
      * Registers a remote animation to be run for all activity starts from a certain package during
      * a short predefined amount of time.
      */
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index c9bd92a..5a8ac54 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -22,9 +22,12 @@
 import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.ActivityType;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
 import android.util.ArraySet;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.WindowManager.TransitionType;
 
@@ -124,6 +127,20 @@
         }
     }
 
+    /**
+     * Links the death of the runner to the provided death recipient.
+     */
+    public void linkToDeath(IBinder.DeathRecipient deathRecipient) {
+        try {
+            for (int i = 0; i < mTransitionAnimationMap.size(); i++) {
+                mTransitionAnimationMap.valueAt(i).adapter.getRunner().asBinder()
+                        .linkToDeath(deathRecipient, 0 /* flags */);
+            }
+        } catch (RemoteException e) {
+            Slog.e("RemoteAnimationDefinition", "Failed to link to death recipient");
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
index 18dc185..0c7e56e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
@@ -37,6 +37,13 @@
     }
 
     /**
+     * @see Activity#unregisterRemoteAnimations
+     */
+    public void unregisterRemoteAnimations() {
+        mWrapped.unregisterRemoteAnimations();
+    }
+
+    /**
      * @see android.view.ViewDebug#dumpv2(View, ByteArrayOutputStream)
      */
     public boolean encodeViewHierarchy(ByteArrayOutputStream out) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bfc6268..8b73643 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6063,6 +6063,13 @@
 
     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
         mRemoteAnimationDefinition = definition;
+        if (definition != null) {
+            definition.linkToDeath(this::unregisterRemoteAnimations);
+        }
+    }
+
+    void unregisterRemoteAnimations() {
+        mRemoteAnimationDefinition = null;
     }
 
     RemoteAnimationDefinition getRemoteAnimationDefinition() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e02456e..2e53cd5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4683,6 +4683,24 @@
     }
 
     @Override
+    public void unregisterRemoteAnimations(IBinder token) {
+        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "unregisterRemoteAnimations");
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                r.unregisterRemoteAnimations();
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
     public void registerRemoteAnimationForNextActivityStart(String packageName,
             RemoteAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,