Loading services/core/java/com/android/server/wm/ActionChain.java +68 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.server.wm; import static android.view.WindowManager.transitTypeToString; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Trace; import android.util.Slog; import com.android.window.flags.Flags; Loading Loading @@ -216,6 +219,18 @@ public class ActionChain { } } /** * @return The chain link where this chain was first associated with a transition. */ private ActionChain getTransitionSource() { if (mTransition == null) return null; ActionChain out = this; while (out.mPrevious != null && out.mPrevious.mTransition != null) { out = out.mPrevious; } return out; } private static class AsyncStart { final int mStackPos; long mThreadId; Loading Loading @@ -243,6 +258,8 @@ public class ActionChain { /** Stack of suspended actions for dealing with async-start "gaps". */ private final ArrayList<AsyncStart> mAsyncStarts = new ArrayList<>(); private final Stats mStats = new Stats(); Tracker(ActivityTaskManagerService atm) { mAtm = atm; } Loading Loading @@ -364,7 +381,14 @@ public class ActionChain { */ @NonNull ActionChain start(String source, Transition transit) { return makeChain(source, TYPE_NORMAL, transit); boolean isTransitionNew = transit.mChainHead == null; final ActionChain out = makeChain(source, TYPE_NORMAL, transit); if (isTransitionNew) { mStats.onTransitionCreated(out); } else { mStats.onTransitionContinued(out); } return out; } /** @see #TYPE_DEFAULT */ Loading @@ -375,11 +399,15 @@ public class ActionChain { /** * Create a chain-link for a decision-point between making a new transition or using the * global collecting one. * global collecting one. A new transition is the desired outcome in this case. */ @NonNull ActionChain startTransit(String source) { return makeChain(source, TYPE_DEFAULT); final ActionChain out = makeChain(source, TYPE_DEFAULT); if (out.isCollecting()) { mStats.onTransitionCombined(out); } return out; } /** Loading Loading @@ -414,4 +442,41 @@ public class ActionChain { static ActionChain testFinish(Transition toFinish) { return new ActionChain("test", TYPE_FINISH, toFinish); } static class Stats { void onTransitionCreated(ActionChain head) { } /** * A chain link was added for a unique transition that was forced to be combined into an * already-collecting transition. */ void onTransitionCombined(ActionChain head) { final Transition transit = head.getTransition(); final String tsum = transitSummary(transit); final ActionChain tsource = head.getTransitionSource(); Trace.instantForTrack(Trace.TRACE_TAG_WINDOW_MANAGER, "TransitCombine", head.mSource + "->" + tsum + ":" + tsource.mSource); Slog.w(TAG, "Combining " + head.mSource + " into " + "#" + transit.getSyncId() + "(" + tsum + ") from " + tsource.mSource); } /** * A chain link was added to continue an already-collecting transition. */ void onTransitionContinued(ActionChain head) { if (!Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { return; } final String tsum = transitSummary(head.getTransition()); final ActionChain tsource = head.getTransitionSource(); Trace.instantForTrack(Trace.TRACE_TAG_WINDOW_MANAGER, "TransitContinue", head.mSource + "->" + tsum + ":" + tsource.mSource); } private static String transitSummary(Transition t) { return transitTypeToString(t.mType) + "|" + (t.mLogger.mFromPlayer ? "" : "R") + "|0x" + Integer.toHexString(t.getFlags()); } } } services/core/java/com/android/server/wm/ActivityRecord.java +10 −1 Original line number Diff line number Diff line Loading @@ -3587,7 +3587,16 @@ final class ActivityRecord extends WindowToken { // root task is not visible if it only contains finishing activities. && mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask); final ActionChain chain = mAtmService.mChainTracker.startTransit("AR.finish"); final ActionChain chain; final Transition sourceTransit = mTransitionController.getCollectingTransition(); if (sourceTransit != null && (sourceTransit.isSourceActivity(this) || sourceTransit.isInTransition(this))) { // TODO(b/294925498): Until we have accurate ready tracking, assume that // membership or "sourceActivity" means this is expected. chain = mAtmService.mChainTracker.start("AR.finish-" + reason, sourceTransit); } else { chain = mAtmService.mChainTracker.startTransit("AR.finish-" + reason); } mAtmService.deferWindowLayout(); try { mTaskSupervisor.mNoHistoryActivities.remove(this); Loading services/core/java/com/android/server/wm/ActivityStarter.java +16 −2 Original line number Diff line number Diff line Loading @@ -1508,22 +1508,36 @@ class ActivityStarter { mService.resumeAppSwitches(); } final ActionChain chain = mService.mChainTracker.startTransit("startAct"); // Because startActivity must run immediately, it can get combined with another // transition meaning it is no-longer independent. This is NOT desirable, but is the // only option for the time being. boolean isIndependent = false; final ActionChain chain; final Transition sourceTransit = r.mTransitionController.getCollectingTransition(); final String actionType = r.isActivityTypeHomeOrRecents() ? "startHomeAct" : "startAct"; if (sourceRecord != null && sourceTransit != null && sourceTransit.isInTransition(sourceRecord)) { // TODO(b/294925498): Until we have accurate ready tracking, assume that // sourceRecord membership means this is expected. chain = mService.mChainTracker.start(actionType, sourceTransit); } else { chain = mService.mChainTracker.startTransit(actionType); } if (!chain.isCollecting()) { // Only do the create here since startActivityInner can abort. If it doesn't abort, // the requestStart will be sent in handleStartRequest. chain.attachTransition(r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN)); isIndependent = chain.getTransition() != null; } final Transition transition = chain.getTransition(); if (transition != null && sourceRecord != null) { transition.addSourceActivity(sourceRecord); } mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, checkedOptions, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, chain.getTransition(), isIndependent); transition, isIndependent); // Because the pending-intent usage in the waitAsyncStart hack "exits" ATMS into // AMS and re-enters, this can be nested. Loading services/core/java/com/android/server/wm/Transition.java +27 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { /** The current head of the chain of actions related to this transition. */ ActionChain mChainHead = null; /** * List of activities which have initiated actions in this transition. For now, assume that * if an activity has initiated at-least one action in this transition, any following actions * initiated by that activity (during collection) are intentionally in the same transition. */ ArrayList<ActivityRecord> mSourceActivities = null; @VisibleForTesting Transition(@TransitionType int type, @TransitionFlags int flags, TransitionController controller, BLASTSyncEngine syncEngine) { Loading Loading @@ -973,6 +980,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } /** * Record an activity as being a source of actions in this transition. */ void addSourceActivity(ActivityRecord r) { if (mSourceActivities == null) { mSourceActivities = new ArrayList<>(); } else if (mSourceActivities.contains(r)) { return; } mSourceActivities.add(r); } /** * @return whether {@param r} is a source of actions in this transition. */ boolean isSourceActivity(ActivityRecord r) { if (mSourceActivities == null) return false; return mSourceActivities.contains(r); } /** * @return {@code true} if `wc` is a participant or is a descendant of one. */ Loading services/core/java/com/android/server/wm/TransitionController.java +1 −0 Original line number Diff line number Diff line Loading @@ -1753,6 +1753,7 @@ class TransitionController { WindowContainerTransaction mStartWCT; int mSyncId; TransitionInfo mInfo; boolean mFromPlayer; private String buildOnSendLog() { StringBuilder sb = new StringBuilder("Sent Transition (#").append(mSyncId) Loading Loading
services/core/java/com/android/server/wm/ActionChain.java +68 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.server.wm; import static android.view.WindowManager.transitTypeToString; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Trace; import android.util.Slog; import com.android.window.flags.Flags; Loading Loading @@ -216,6 +219,18 @@ public class ActionChain { } } /** * @return The chain link where this chain was first associated with a transition. */ private ActionChain getTransitionSource() { if (mTransition == null) return null; ActionChain out = this; while (out.mPrevious != null && out.mPrevious.mTransition != null) { out = out.mPrevious; } return out; } private static class AsyncStart { final int mStackPos; long mThreadId; Loading Loading @@ -243,6 +258,8 @@ public class ActionChain { /** Stack of suspended actions for dealing with async-start "gaps". */ private final ArrayList<AsyncStart> mAsyncStarts = new ArrayList<>(); private final Stats mStats = new Stats(); Tracker(ActivityTaskManagerService atm) { mAtm = atm; } Loading Loading @@ -364,7 +381,14 @@ public class ActionChain { */ @NonNull ActionChain start(String source, Transition transit) { return makeChain(source, TYPE_NORMAL, transit); boolean isTransitionNew = transit.mChainHead == null; final ActionChain out = makeChain(source, TYPE_NORMAL, transit); if (isTransitionNew) { mStats.onTransitionCreated(out); } else { mStats.onTransitionContinued(out); } return out; } /** @see #TYPE_DEFAULT */ Loading @@ -375,11 +399,15 @@ public class ActionChain { /** * Create a chain-link for a decision-point between making a new transition or using the * global collecting one. * global collecting one. A new transition is the desired outcome in this case. */ @NonNull ActionChain startTransit(String source) { return makeChain(source, TYPE_DEFAULT); final ActionChain out = makeChain(source, TYPE_DEFAULT); if (out.isCollecting()) { mStats.onTransitionCombined(out); } return out; } /** Loading Loading @@ -414,4 +442,41 @@ public class ActionChain { static ActionChain testFinish(Transition toFinish) { return new ActionChain("test", TYPE_FINISH, toFinish); } static class Stats { void onTransitionCreated(ActionChain head) { } /** * A chain link was added for a unique transition that was forced to be combined into an * already-collecting transition. */ void onTransitionCombined(ActionChain head) { final Transition transit = head.getTransition(); final String tsum = transitSummary(transit); final ActionChain tsource = head.getTransitionSource(); Trace.instantForTrack(Trace.TRACE_TAG_WINDOW_MANAGER, "TransitCombine", head.mSource + "->" + tsum + ":" + tsource.mSource); Slog.w(TAG, "Combining " + head.mSource + " into " + "#" + transit.getSyncId() + "(" + tsum + ") from " + tsource.mSource); } /** * A chain link was added to continue an already-collecting transition. */ void onTransitionContinued(ActionChain head) { if (!Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { return; } final String tsum = transitSummary(head.getTransition()); final ActionChain tsource = head.getTransitionSource(); Trace.instantForTrack(Trace.TRACE_TAG_WINDOW_MANAGER, "TransitContinue", head.mSource + "->" + tsum + ":" + tsource.mSource); } private static String transitSummary(Transition t) { return transitTypeToString(t.mType) + "|" + (t.mLogger.mFromPlayer ? "" : "R") + "|0x" + Integer.toHexString(t.getFlags()); } } }
services/core/java/com/android/server/wm/ActivityRecord.java +10 −1 Original line number Diff line number Diff line Loading @@ -3587,7 +3587,16 @@ final class ActivityRecord extends WindowToken { // root task is not visible if it only contains finishing activities. && mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask); final ActionChain chain = mAtmService.mChainTracker.startTransit("AR.finish"); final ActionChain chain; final Transition sourceTransit = mTransitionController.getCollectingTransition(); if (sourceTransit != null && (sourceTransit.isSourceActivity(this) || sourceTransit.isInTransition(this))) { // TODO(b/294925498): Until we have accurate ready tracking, assume that // membership or "sourceActivity" means this is expected. chain = mAtmService.mChainTracker.start("AR.finish-" + reason, sourceTransit); } else { chain = mAtmService.mChainTracker.startTransit("AR.finish-" + reason); } mAtmService.deferWindowLayout(); try { mTaskSupervisor.mNoHistoryActivities.remove(this); Loading
services/core/java/com/android/server/wm/ActivityStarter.java +16 −2 Original line number Diff line number Diff line Loading @@ -1508,22 +1508,36 @@ class ActivityStarter { mService.resumeAppSwitches(); } final ActionChain chain = mService.mChainTracker.startTransit("startAct"); // Because startActivity must run immediately, it can get combined with another // transition meaning it is no-longer independent. This is NOT desirable, but is the // only option for the time being. boolean isIndependent = false; final ActionChain chain; final Transition sourceTransit = r.mTransitionController.getCollectingTransition(); final String actionType = r.isActivityTypeHomeOrRecents() ? "startHomeAct" : "startAct"; if (sourceRecord != null && sourceTransit != null && sourceTransit.isInTransition(sourceRecord)) { // TODO(b/294925498): Until we have accurate ready tracking, assume that // sourceRecord membership means this is expected. chain = mService.mChainTracker.start(actionType, sourceTransit); } else { chain = mService.mChainTracker.startTransit(actionType); } if (!chain.isCollecting()) { // Only do the create here since startActivityInner can abort. If it doesn't abort, // the requestStart will be sent in handleStartRequest. chain.attachTransition(r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN)); isIndependent = chain.getTransition() != null; } final Transition transition = chain.getTransition(); if (transition != null && sourceRecord != null) { transition.addSourceActivity(sourceRecord); } mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, checkedOptions, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, chain.getTransition(), isIndependent); transition, isIndependent); // Because the pending-intent usage in the waitAsyncStart hack "exits" ATMS into // AMS and re-enters, this can be nested. Loading
services/core/java/com/android/server/wm/Transition.java +27 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { /** The current head of the chain of actions related to this transition. */ ActionChain mChainHead = null; /** * List of activities which have initiated actions in this transition. For now, assume that * if an activity has initiated at-least one action in this transition, any following actions * initiated by that activity (during collection) are intentionally in the same transition. */ ArrayList<ActivityRecord> mSourceActivities = null; @VisibleForTesting Transition(@TransitionType int type, @TransitionFlags int flags, TransitionController controller, BLASTSyncEngine syncEngine) { Loading Loading @@ -973,6 +980,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } /** * Record an activity as being a source of actions in this transition. */ void addSourceActivity(ActivityRecord r) { if (mSourceActivities == null) { mSourceActivities = new ArrayList<>(); } else if (mSourceActivities.contains(r)) { return; } mSourceActivities.add(r); } /** * @return whether {@param r} is a source of actions in this transition. */ boolean isSourceActivity(ActivityRecord r) { if (mSourceActivities == null) return false; return mSourceActivities.contains(r); } /** * @return {@code true} if `wc` is a participant or is a descendant of one. */ Loading
services/core/java/com/android/server/wm/TransitionController.java +1 −0 Original line number Diff line number Diff line Loading @@ -1753,6 +1753,7 @@ class TransitionController { WindowContainerTransaction mStartWCT; int mSyncId; TransitionInfo mInfo; boolean mFromPlayer; private String buildOnSendLog() { StringBuilder sb = new StringBuilder("Sent Transition (#").append(mSyncId) Loading