RemoteAnimations: Add failsafe
Adds failsafe mechanisms to RemoteAnimation and RecentsAnimation:
- cancel animations on binder death
- schedule a short timeout for RecentsAnimation after HOME and POWER events
Also enables RemoteAnimationControllerTest for presubmit, since it's turned
out to be reliable.
Change-Id: Id0bfdbee7d36f662eb386727195da8de2ed1684a
Fixes: 73496879
Test: kill / suspend launcher during animations; verify animations get aborted as expected.
Test: atest RemoteAnimationControllerTest
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 379a1a1..3be7b235 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -26,6 +26,7 @@
import android.graphics.Rect;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
@@ -47,7 +48,7 @@
/**
* Helper class to run app animations in a remote process.
*/
-class RemoteAnimationController {
+class RemoteAnimationController implements DeathRecipient {
private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM;
private static final long TIMEOUT_MS = 2000;
@@ -56,12 +57,10 @@
private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>();
private final Rect mTmpRect = new Rect();
private final Handler mHandler;
- private FinishedCallback mFinishedCallback;
+ private final Runnable mTimeoutRunnable = this::cancelAnimation;
- private final Runnable mTimeoutRunnable = () -> {
- onAnimationFinished();
- invokeAnimationCancelled();
- };
+ private FinishedCallback mFinishedCallback;
+ private boolean mCanceled;
RemoteAnimationController(WindowManagerService service,
RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
@@ -90,7 +89,7 @@
* Called when the transition is ready to be started, and all leashes have been set up.
*/
void goodToGo() {
- if (mPendingAnimations.isEmpty()) {
+ if (mPendingAnimations.isEmpty() || mCanceled) {
onAnimationFinished();
return;
}
@@ -107,8 +106,8 @@
}
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
try {
- mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
- mFinishedCallback);
+ mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0);
+ mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, mFinishedCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to start remote animation", e);
onAnimationFinished();
@@ -120,6 +119,17 @@
}
}
+ private void cancelAnimation() {
+ synchronized (mService.getWindowManagerLock()) {
+ if (mCanceled) {
+ return;
+ }
+ mCanceled = true;
+ }
+ onAnimationFinished();
+ invokeAnimationCancelled();
+ }
+
private void writeStartDebugStatement() {
Slog.i(TAG, "Starting remote animation");
final StringWriter sw = new StringWriter();
@@ -154,6 +164,7 @@
private void onAnimationFinished() {
mHandler.removeCallbacks(mTimeoutRunnable);
+ mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0);
synchronized (mService.mWindowMap) {
releaseFinishedCallback();
mService.openSurfaceTransaction();
@@ -193,6 +204,11 @@
mService.sendSetRunningRemoteAnimation(pid, running);
}
+ @Override
+ public void binderDied() {
+ cancelAnimation();
+ }
+
private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
RemoteAnimationController mOuter;