Prevent double-applying transactions

With BLAST, transactions contain buffers. Since we pass the transaction
between processes, its possible to commit the transaction twice. If the
transaction contains buffers, it will confuse surfaceflinger.

Account for this by clearing transactions when they are sent to remotes.
The merge case is non-trivial, though, because the remote may not
actually merge. So, for that, we clear the transaction only when it
is merged.

Fixing this revealed a bug in an edge-case triggered by tapltests, so this
fixes that as well.

Bug: 238328090
Test: atest TaplTestsLauncher3
Change-Id: If30b0bd4e8fad4658365826a25eac38dc06af4c7
This commit is contained in:
Evan Rosky
2022-07-13 20:48:40 -07:00
parent aec1a526b9
commit 1cf47ef3fc
3 changed files with 37 additions and 0 deletions

View File

@@ -99,6 +99,8 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
+ " during unit tests");
}
mRemote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
// assume that remote will apply the start transaction.
startTransaction.clear();
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
if (mRemote.asBinder() != null) {
@@ -120,6 +122,11 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
@Override
public void onTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction sct) {
// We have merged, since we sent the transaction over binder, the one in this
// process won't be cleared if the remote applied it. We don't actually know if the
// remote applied the transaction, but applying twice will break surfaceflinger
// so just assume the worst-case and clear the local transaction.
t.clear();
mMainExecutor.execute(
() -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
}

View File

@@ -139,6 +139,8 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+ " during unit tests");
}
remote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
// assume that remote will apply the start transaction.
startTransaction.clear();
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
unhandleDeath(remote.asBinder(), finishCallback);
@@ -162,6 +164,11 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
@Override
public void onTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction sct) {
// We have merged, since we sent the transaction over binder, the one in this
// process won't be cleared if the remote applied it. We don't actually know if the
// remote applied the transaction, but applying twice will break surfaceflinger
// so just assume the worst-case and clear the local transaction.
t.clear();
mMainExecutor.execute(() -> {
if (!mRequestedRemotes.containsKey(mergeTarget)) {
Log.e(TAG, "Merged transition finished after it's mergeTarget (the "

View File

@@ -224,6 +224,7 @@ public class RemoteTransitionCompat implements Parcelable {
private WindowContainerToken mRecentsTask = null;
private TransitionInfo mInfo = null;
private ArrayList<SurfaceControl> mOpeningLeashes = null;
private boolean mOpeningHome = false;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
@@ -321,6 +322,7 @@ public class RemoteTransitionCompat implements Parcelable {
}
final int layer = mInfo.getChanges().size() * 3;
mOpeningLeashes = new ArrayList<>();
mOpeningHome = cancelRecents;
final RemoteAnimationTargetCompat[] targets =
new RemoteAnimationTargetCompat[openingTasks.size()];
for (int i = 0; i < openingTasks.size(); ++i) {
@@ -406,6 +408,26 @@ public class RemoteTransitionCompat implements Parcelable {
if (!mKeyguardLocked && mRecentsTask != null) {
wct.restoreTransientOrder(mRecentsTask);
}
} else if (toHome && mOpeningHome && mPausingTasks != null) {
// Special situaition where 3p launcher was changed during recents (this happens
// during tapltests...). Here we get both "return to home" AND "home opening".
// This is basically going home, but we have to restore recents order and also
// treat the home "pausing" task properly.
for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = mInfo.getChange(mPausingTasks.get(i));
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
// Treat as opening (see above)
wct.reorder(mPausingTasks.get(i), true /* onTop */);
t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
} else {
// Treat as hiding (see below)
t.hide(mInfo.getChange(mPausingTasks.get(i)).getLeash());
}
}
if (!mKeyguardLocked && mRecentsTask != null) {
wct.restoreTransientOrder(mRecentsTask);
}
} else {
for (int i = 0; i < mPausingTasks.size(); ++i) {
if (!sendUserLeaveHint) {
@@ -444,6 +466,7 @@ public class RemoteTransitionCompat implements Parcelable {
mPausingTasks = null;
mInfo = null;
mOpeningLeashes = null;
mOpeningHome = false;
mLeashMap = null;
mTransition = null;
}