• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.util.Slog;
23 
24 import com.android.window.flags.Flags;
25 
26 /**
27  * Represents a chain of WM actions where each action is "caused by" the prior action (except the
28  * first one of course). A whole chain is associated with one Transition (in fact, the purpose
29  * of this object is to communicate, to all callees, which transition they are part of).
30  *
31  * A single action is defined as "one logical thing requested of WM". This usually corresponds to
32  * each ingress-point into the process. For example, when starting an activity:
33  *   * the first action is to pause the current/top activity.
34  *       At this point, control leaves the process while the activity pauses.
35  *   * Then WM receives completePause (a new ingress). This is a new action that gets linked
36  *       to the prior action. This action involves resuming the next activity, at which point,
37  *       control leaves the process again.
38  *   * Eventually, when everything is done, we will have formed a chain of actions.
39  *
40  * We don't technically need to hold onto each prior action in the chain once a new action has
41  * been linked to the same transition; however, keeping the whole chain enables improved
42  * debugging and the ability to detect anomalies.
43  */
44 public class ActionChain {
45     private static final String TAG = "TransitionChain";
46 
47     /**
48      * Normal link type. This means the action was expected and is properly linked to the
49      * current chain.
50      */
51     static final int TYPE_NORMAL = 0;
52 
53     /**
54      * This is the "default" link. It means we haven't done anything to properly track this case
55      * so it may or may not be correct. It represents the behavior as if there was no tracking.
56      *
57      * Any type that has "default" behavior uses the global "collecting transition" if it exists,
58      * otherwise it doesn't use any transition.
59      */
60     static final int TYPE_DEFAULT = 1;
61 
62     /**
63      * This means the action was performed via a legacy code-path. These should be removed
64      * eventually. This will have the "default" behavior.
65      */
66     static final int TYPE_LEGACY = 2;
67 
68     /** This is for a test. */
69     static final int TYPE_TEST = 3;
70 
71     /** This is finishing a transition. Collection isn't supported during this. */
72     static final int TYPE_FINISH = 4;
73 
74     /**
75      * Something unexpected happened so this action was started to recover from the unexpected
76      * state. This means that a "real" chain-link couldn't be determined. For now, the behavior of
77      * this is the same as "default".
78      */
79     static final int TYPE_FAILSAFE = 5;
80 
81     /**
82      * Types of chain links (ie. how is this action associated with the chain it is linked to).
83      * @hide
84      */
85     @IntDef(prefix = { "TYPE_" }, value = {
86             TYPE_NORMAL,
87             TYPE_DEFAULT,
88             TYPE_LEGACY,
89             TYPE_TEST,
90             TYPE_FINISH,
91             TYPE_FAILSAFE
92     })
93     public @interface LinkType {}
94 
95     /** Identifies the entry-point of this action. */
96     @NonNull
97     final String mSource;
98 
99     /** Reference to ATMS. TEMPORARY! ONLY USE THIS WHEN tracker_plumbing flag is DISABLED! */
100     @Nullable
101     ActivityTaskManagerService mTmpAtm;
102 
103     /** The transition that this chain's changes belong to. */
104     @Nullable
105     Transition mTransition;
106 
107     /** The previous action in the chain. */
108     @Nullable
109     ActionChain mPrevious = null;
110 
111     /** Classification of how this action is connected to the chain. */
112     @LinkType int mType = TYPE_NORMAL;
113 
114     /** When this Action started. */
115     long mCreateTimeMs;
116 
ActionChain(String source, @LinkType int type, Transition transit)117     private ActionChain(String source, @LinkType int type, Transition transit) {
118         mSource = source;
119         mCreateTimeMs = System.currentTimeMillis();
120         mType = type;
121         mTransition = transit;
122         if (mTransition != null) {
123             mTransition.recordChain(this);
124         }
125     }
126 
getTransition()127     private Transition getTransition() {
128         if (!Flags.transitTrackerPlumbing()) {
129             return mTmpAtm.getTransitionController().getCollectingTransition();
130         }
131         return mTransition;
132     }
133 
isFinishing()134     boolean isFinishing() {
135         return mType == TYPE_FINISH;
136     }
137 
138     /**
139      * Some common checks to determine (and report) whether this chain has a collecting transition.
140      */
expectCollecting()141     private boolean expectCollecting() {
142         final Transition transition = getTransition();
143         if (transition == null) {
144             Slog.e(TAG, "Can't collect into a chain with no transition");
145             return false;
146         }
147         if (isFinishing()) {
148             Slog.e(TAG, "Trying to collect into a finished transition");
149             return false;
150         }
151         if (transition.mController.getCollectingTransition() != mTransition) {
152             Slog.e(TAG, "Mismatch between current collecting ("
153                     + transition.mController.getCollectingTransition() + ") and chain ("
154                     + transition + ")");
155             return false;
156         }
157         return true;
158     }
159 
160     /**
161      * Helper to collect a container into the associated transition. This will automatically do
162      * nothing if the chain isn't associated with a collecting transition.
163      */
collect(@onNull WindowContainer wc)164     void collect(@NonNull WindowContainer wc) {
165         if (!wc.mTransitionController.isShellTransitionsEnabled()) return;
166         if (!expectCollecting()) return;
167         getTransition().collect(wc);
168     }
169 
170     /**
171      * An interface for creating and tracking action chains.
172      */
173     static class Tracker {
174         private final ActivityTaskManagerService mAtm;
175 
Tracker(ActivityTaskManagerService atm)176         Tracker(ActivityTaskManagerService atm) {
177             mAtm = atm;
178         }
179 
makeChain(String source, @LinkType int type, Transition transit)180         private ActionChain makeChain(String source, @LinkType int type, Transition transit) {
181             final ActionChain out = new ActionChain(source, type, transit);
182             if (!Flags.transitTrackerPlumbing()) {
183                 out.mTmpAtm = mAtm;
184             }
185             return out;
186         }
187 
makeChain(String source, @LinkType int type)188         private ActionChain makeChain(String source, @LinkType int type) {
189             return makeChain(source, type,
190                     mAtm.getTransitionController().getCollectingTransition());
191         }
192 
193         /**
194          * Starts tracking a normal action.
195          * @see #TYPE_NORMAL
196          */
197         @NonNull
start(String source, Transition transit)198         ActionChain start(String source, Transition transit) {
199             return makeChain(source, TYPE_NORMAL, transit);
200         }
201 
202         /** @see #TYPE_DEFAULT */
203         @NonNull
startDefault(String source)204         ActionChain startDefault(String source) {
205             return makeChain(source, TYPE_DEFAULT);
206         }
207 
208         /**
209          * Starts tracking an action that finishes a transition.
210          * @see #TYPE_NORMAL
211          */
212         @NonNull
startFinish(String source, Transition finishTransit)213         ActionChain startFinish(String source, Transition finishTransit) {
214             return makeChain(source, TYPE_FINISH, finishTransit);
215         }
216 
217         /** @see #TYPE_LEGACY */
218         @NonNull
startLegacy(String source)219         ActionChain startLegacy(String source) {
220             return makeChain(source, TYPE_LEGACY, null);
221         }
222 
223         /** @see #TYPE_FAILSAFE */
224         @NonNull
startFailsafe(String source)225         ActionChain startFailsafe(String source) {
226             return makeChain(source, TYPE_FAILSAFE);
227         }
228     }
229 
230     /** Helpers for usage in tests. */
231     @NonNull
test()232     static ActionChain test() {
233         return new ActionChain("test", TYPE_TEST, null /* transition */);
234     }
235 
236     @NonNull
testFinish(Transition toFinish)237     static ActionChain testFinish(Transition toFinish) {
238         return new ActionChain("test", TYPE_FINISH, toFinish);
239     }
240 }
241