Merge "Catch exception for deferred window transaction" into udc-dev

This commit is contained in:
Riddle Hsu
2023-06-15 12:15:27 +00:00
committed by Android (Google) Code Review
3 changed files with 50 additions and 15 deletions

View File

@@ -58,6 +58,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.server.FgThread; import com.android.server.FgThread;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.LongConsumer; import java.util.function.LongConsumer;
/** /**
@@ -1314,18 +1315,18 @@ class TransitionController {
return transit; return transit;
} }
/** Returns {@code true} if it started collecting, {@code false} if it was queued. */ /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */
boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) { void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) {
if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) { if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) {
// Just add to queue since we already have a queue. // Just add to queue since we already have a queue.
mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run())); mQueuedTransitions.add(new QueuedTransition(syncGroup,
(deferred) -> applySync.accept(true /* deferred */)));
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
"Queueing legacy sync-set: %s", syncGroup.mSyncId); "Queueing legacy sync-set: %s", syncGroup.mSyncId);
return false; return;
} }
mSyncEngine.startSyncSet(syncGroup); mSyncEngine.startSyncSet(syncGroup);
applySync.run(); applySync.accept(false /* deferred */);
return true;
} }
interface OnStartCollect { interface OnStartCollect {

View File

@@ -232,8 +232,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback); final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
final int syncId = syncGroup.mSyncId; final int syncId = syncGroup.mSyncId;
if (mTransitionController.isShellTransitionsEnabled()) { if (mTransitionController.isShellTransitionsEnabled()) {
mTransitionController.startLegacySyncOrQueue(syncGroup, () -> { mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> {
applyTransaction(t, syncId, null /*transition*/, caller); applyTransaction(t, syncId, null /* transition */, caller, deferred);
setSyncReady(syncId); setSyncReady(syncId);
}); });
} else { } else {
@@ -304,7 +304,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
(deferred) -> { (deferred) -> {
nextTransition.start(); nextTransition.start();
nextTransition.mLogger.mStartWCT = wct; nextTransition.mLogger.mStartWCT = wct;
applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
deferred);
if (needsSetReady) { if (needsSetReady) {
nextTransition.setAllReady(); nextTransition.setAllReady();
} }
@@ -456,7 +457,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
transition.abort(); transition.abort();
return; return;
} }
if (applyTransaction(wct, -1 /* syncId */, transition, caller) if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred)
== TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) { == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
transition.abort(); transition.abort();
return; return;
@@ -476,6 +477,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return applyTransaction(t, syncId, transition, caller, null /* finishTransition */); return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
} }
private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {
if (deferred) {
try {
return applyTransaction(t, syncId, transition, caller);
} catch (RuntimeException e) {
// If the transaction is deferred, the caller could be from TransitionController
// #tryStartCollectFromQueue that executes on system's worker thread rather than
// binder thread. And the operation in the WCT may be outdated that violates the
// current state. So catch the exception to avoid crashing the system.
Slog.e(TAG, "Failed to execute deferred applyTransaction", e);
}
return TRANSACT_EFFECTS_NONE;
}
return applyTransaction(t, syncId, transition, caller);
}
/** /**
* @param syncId If non-null, this will be a sync-transaction. * @param syncId If non-null, this will be a sync-transaction.
* @param transition A transition to collect changes into. * @param transition A transition to collect changes into.
@@ -838,13 +856,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
switch (type) { switch (type) {
case HIERARCHY_OP_TYPE_REMOVE_TASK: { case HIERARCHY_OP_TYPE_REMOVE_TASK: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
final Task task = wc != null ? wc.asTask() : null; if (wc == null || wc.asTask() == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to remove invalid task: " + wc);
break;
}
final Task task = wc.asTask();
task.remove(true, "Applying remove task Hierarchy Op"); task.remove(true, "Applying remove task Hierarchy Op");
break; break;
} }
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc);
break;
}
final Task task = wc.asTask();
if (task == null) { if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
} else if (task.getTaskDisplayArea() == null) { } else if (task.getTaskDisplayArea() == null) {
@@ -858,7 +884,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
} }
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: { case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc);
break;
}
final Task task = wc.asTask();
final boolean clearRoot = hop.getToTop(); final boolean clearRoot = hop.getToTop();
if (task == null) { if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);

View File

@@ -2191,8 +2191,11 @@ public class TransitionTests extends WindowTestsBase {
BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet( BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet(
mock(BLASTSyncEngine.TransactionReadyListener.class), "test"); mock(BLASTSyncEngine.TransactionReadyListener.class), "test");
final boolean[] applyLegacy = new boolean[]{false}; final boolean[] applyLegacy = new boolean[2];
controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true); controller.startLegacySyncOrQueue(legacySync, (deferred) -> {
applyLegacy[0] = true;
applyLegacy[1] = deferred;
});
assertFalse(applyLegacy[0]); assertFalse(applyLegacy[0]);
waitUntilHandlersIdle(); waitUntilHandlersIdle();
@@ -2208,6 +2211,7 @@ public class TransitionTests extends WindowTestsBase {
assertTrue(transitA.isPlaying()); assertTrue(transitA.isPlaying());
// legacy sync should start now // legacy sync should start now
assertTrue(applyLegacy[0]); assertTrue(applyLegacy[0]);
assertTrue(applyLegacy[1]);
// transitB must wait // transitB must wait
assertTrue(transitB.isPending()); assertTrue(transitB.isPending());